From 19cd15bdeb48c7858251de6d5bb676773ca4665b Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Fri, 10 Oct 2025 14:35:45 -0500 Subject: [PATCH] fix(lazer): Support int/string/null/missing jrpc id field in success/error responses --- Cargo.lock | 10 +- .../pyth-lazer-solana-contract/Cargo.toml | 2 +- lazer/publisher_sdk/rust/Cargo.toml | 4 +- lazer/sdk/rust/client/Cargo.toml | 4 +- lazer/sdk/rust/protocol/Cargo.toml | 2 +- lazer/sdk/rust/protocol/src/jrpc.rs | 113 +++++++++++++++++- 6 files changed, 118 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d6e0fb75c..01571c1f9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5693,7 +5693,7 @@ dependencies = [ [[package]] name = "pyth-lazer-client" -version = "8.3.0" +version = "8.4.0" dependencies = [ "alloy-primitives 0.8.25", "anyhow", @@ -5711,7 +5711,7 @@ dependencies = [ "hex", "humantime-serde", "libsecp256k1 0.7.2", - "pyth-lazer-protocol 0.17.0", + "pyth-lazer-protocol 0.18.0", "reqwest 0.12.23", "serde", "serde_json", @@ -5746,7 +5746,7 @@ dependencies = [ [[package]] name = "pyth-lazer-protocol" -version = "0.17.0" +version = "0.18.0" dependencies = [ "alloy-primitives 0.8.25", "anyhow", @@ -5786,13 +5786,13 @@ dependencies = [ [[package]] name = "pyth-lazer-publisher-sdk" -version = "0.15.0" +version = "0.16.0" dependencies = [ "anyhow", "fs-err", "protobuf", "protobuf-codegen", - "pyth-lazer-protocol 0.17.0", + "pyth-lazer-protocol 0.18.0", "serde_json", ] diff --git a/lazer/contracts/solana/programs/pyth-lazer-solana-contract/Cargo.toml b/lazer/contracts/solana/programs/pyth-lazer-solana-contract/Cargo.toml index 38a0f6b1b5..cbfcecccfb 100644 --- a/lazer/contracts/solana/programs/pyth-lazer-solana-contract/Cargo.toml +++ b/lazer/contracts/solana/programs/pyth-lazer-solana-contract/Cargo.toml @@ -19,7 +19,7 @@ no-log-ix-name = [] idl-build = ["anchor-lang/idl-build"] [dependencies] -pyth-lazer-protocol = { path = "../../../../sdk/rust/protocol", version = "0.17.0" } +pyth-lazer-protocol = { path = "../../../../sdk/rust/protocol", version = "0.18.0" } anchor-lang = "0.31.1" bytemuck = { version = "1.20.0", features = ["derive"] } diff --git a/lazer/publisher_sdk/rust/Cargo.toml b/lazer/publisher_sdk/rust/Cargo.toml index b90e1e8a19..b6ced09c55 100644 --- a/lazer/publisher_sdk/rust/Cargo.toml +++ b/lazer/publisher_sdk/rust/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "pyth-lazer-publisher-sdk" -version = "0.15.0" +version = "0.16.0" edition = "2021" description = "Pyth Lazer Publisher SDK types." license = "Apache-2.0" repository = "https://github.com/pyth-network/pyth-crosschain" [dependencies] -pyth-lazer-protocol = { version = "0.17.0", path = "../../sdk/rust/protocol" } +pyth-lazer-protocol = { version = "0.18.0", path = "../../sdk/rust/protocol" } anyhow = "1.0.98" protobuf = "3.7.2" serde_json = "1.0.140" diff --git a/lazer/sdk/rust/client/Cargo.toml b/lazer/sdk/rust/client/Cargo.toml index ff6be20f1b..3a736c3cc5 100644 --- a/lazer/sdk/rust/client/Cargo.toml +++ b/lazer/sdk/rust/client/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "pyth-lazer-client" -version = "8.3.0" +version = "8.4.0" edition = "2021" description = "A Rust client for Pyth Lazer" license = "Apache-2.0" [dependencies] -pyth-lazer-protocol = { path = "../protocol", version = "0.17.0" } +pyth-lazer-protocol = { path = "../protocol", version = "0.18.0" } tokio = { version = "1", features = ["full"] } tokio-tungstenite = { version = "0.20", features = ["native-tls"] } futures-util = "0.3" diff --git a/lazer/sdk/rust/protocol/Cargo.toml b/lazer/sdk/rust/protocol/Cargo.toml index bc05f638c6..00b25998e8 100644 --- a/lazer/sdk/rust/protocol/Cargo.toml +++ b/lazer/sdk/rust/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyth-lazer-protocol" -version = "0.17.0" +version = "0.18.0" edition = "2021" description = "Pyth Lazer SDK - protocol types." license = "Apache-2.0" diff --git a/lazer/sdk/rust/protocol/src/jrpc.rs b/lazer/sdk/rust/protocol/src/jrpc.rs index 3da0e45907..99fd8105e7 100644 --- a/lazer/sdk/rust/protocol/src/jrpc.rs +++ b/lazer/sdk/rust/protocol/src/jrpc.rs @@ -91,14 +91,14 @@ pub enum JrpcResponse { pub struct JrpcSuccessResponse { pub jsonrpc: JsonRpcVersion, pub result: T, - pub id: i64, + pub id: JrpcId, } #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] pub struct JrpcErrorResponse { pub jsonrpc: JsonRpcVersion, pub error: JrpcErrorObject, - pub id: Option, + pub id: JrpcId, } #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] @@ -523,7 +523,37 @@ mod tests { message: "Internal error".to_string(), data: None, }, - id: Some(2), + id: JrpcId::Int(2), + } + ); + } + + #[test] + fn test_response_format_error_string_id() { + let response = serde_json::from_str::( + r#" + { + "jsonrpc": "2.0", + "id": "62b627dc-5599-43dd-b2c2-9c4d30f4fdb4", + "error": { + "message": "Internal error", + "code": -32603 + } + } + "#, + ) + .unwrap(); + + assert_eq!( + response, + JrpcErrorResponse { + jsonrpc: JsonRpcVersion::V2, + error: JrpcErrorObject { + code: -32603, + message: "Internal error".to_string(), + data: None, + }, + id: JrpcId::String("62b627dc-5599-43dd-b2c2-9c4d30f4fdb4".to_string()) } ); } @@ -546,7 +576,30 @@ mod tests { JrpcSuccessResponse:: { jsonrpc: JsonRpcVersion::V2, result: "success".to_string(), - id: 2, + id: JrpcId::Int(2), + } + ); + } + + #[test] + pub fn test_response_format_success_string_id() { + let response = serde_json::from_str::>( + r#" + { + "jsonrpc": "2.0", + "id": "62b627dc-5599-43dd-b2c2-9c4d30f4fdb4", + "result": "success" + } + "#, + ) + .unwrap(); + + assert_eq!( + response, + JrpcSuccessResponse:: { + jsonrpc: JsonRpcVersion::V2, + result: "success".to_string(), + id: JrpcId::String("62b627dc-5599-43dd-b2c2-9c4d30f4fdb4".to_string()), } ); } @@ -568,7 +621,7 @@ mod tests { JrpcResponse::Success(JrpcSuccessResponse:: { jsonrpc: JsonRpcVersion::V2, result: "success".to_string(), - id: 2, + id: JrpcId::Int(2), }) ); @@ -594,7 +647,55 @@ mod tests { message: "Internal error".to_string(), data: None, }, - id: Some(3), + id: JrpcId::Int(3), + }) + ); + } + + #[test] + pub fn test_parse_response_string_id() { + let success_response = serde_json::from_str::>( + r#" + { + "jsonrpc": "2.0", + "id": "id-2", + "result": "success" + }"#, + ) + .unwrap(); + + assert_eq!( + success_response, + JrpcResponse::Success(JrpcSuccessResponse:: { + jsonrpc: JsonRpcVersion::V2, + result: "success".to_string(), + id: JrpcId::String("id-2".to_string()), + }) + ); + + let error_response = serde_json::from_str::>( + r#" + { + "jsonrpc": "2.0", + "id": "id-3", + "error": { + "code": -32603, + "message": "Internal error" + } + }"#, + ) + .unwrap(); + + assert_eq!( + error_response, + JrpcResponse::Error(JrpcErrorResponse { + jsonrpc: JsonRpcVersion::V2, + error: JrpcErrorObject { + code: -32603, + message: "Internal error".to_string(), + data: None, + }, + id: JrpcId::String("id-3".to_string()), }) ); }