Skip to content

Commit 6b1d6c6

Browse files
feat(pyth-lazer-protocol)!: enable subscribing by either price_feed_ids or symbols (#3049)
* feat(pyth-lazer-protocol)!: add optional symbols to request structs, make ids optional * fix: remove InvalidFeedSubscriptionDetails.unknown_symbols * prevent specifying both price feed ids and symbols * feat(protocol): bump ver to 0.15.0, update dependents * chore(pyth-lazer-publisher-sdk): bump protocl version * chore(pyth-lazer-solana-contract): bump protocol version * chore(pyth-lazer-solana-contract): bump version
1 parent 2918672 commit 6b1d6c6

File tree

7 files changed

+69
-38
lines changed

7 files changed

+69
-38
lines changed

Cargo.lock

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lazer/contracts/solana/programs/pyth-lazer-solana-contract/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-lazer-solana-contract"
3-
version = "0.6.0"
3+
version = "0.7.0"
44
edition = "2021"
55
description = "Pyth Lazer Solana contract and SDK."
66
license = "Apache-2.0"
@@ -19,7 +19,7 @@ no-log-ix-name = []
1919
idl-build = ["anchor-lang/idl-build"]
2020

2121
[dependencies]
22-
pyth-lazer-protocol = { path = "../../../../sdk/rust/protocol", version = "0.14.0" }
22+
pyth-lazer-protocol = { path = "../../../../sdk/rust/protocol", version = "0.15.0" }
2323

2424
anchor-lang = "0.31.1"
2525
bytemuck = { version = "1.20.0", features = ["derive"] }

lazer/publisher_sdk/rust/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[package]
22
name = "pyth-lazer-publisher-sdk"
3-
version = "0.11.0"
3+
version = "0.12.0"
44
edition = "2021"
55
description = "Pyth Lazer Publisher SDK types."
66
license = "Apache-2.0"
77
repository = "https://github.com/pyth-network/pyth-crosschain"
88

99
[dependencies]
10-
pyth-lazer-protocol = { version = "0.14.0", path = "../../sdk/rust/protocol" }
10+
pyth-lazer-protocol = { version = "0.15.0", path = "../../sdk/rust/protocol" }
1111
anyhow = "1.0.98"
1212
protobuf = "3.7.2"
1313
serde_json = "1.0.140"

lazer/sdk/rust/client/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[package]
22
name = "pyth-lazer-client"
3-
version = "7.0.0"
3+
version = "8.0.0"
44
edition = "2021"
55
description = "A Rust client for Pyth Lazer"
66
license = "Apache-2.0"
77

88
[dependencies]
9-
pyth-lazer-protocol = { path = "../protocol", version = "0.14.0" }
9+
pyth-lazer-protocol = { path = "../protocol", version = "0.15.0" }
1010
tokio = { version = "1", features = ["full"] }
1111
tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
1212
futures-util = "0.3"

lazer/sdk/rust/client/examples/subscribe_price_feeds.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ async fn main() -> anyhow::Result<()> {
5656
pin!(stream);
5757

5858
let subscription_requests = vec![
59-
// Example subscription: Parsed JSON feed targeting Solana
59+
// Example subscription: Parsed JSON feed targeting Solana, specified by price feed ids
6060
SubscribeRequest {
6161
subscription_id: SubscriptionId(1),
6262
params: SubscriptionParams::new(SubscriptionParamsRepr {
63-
price_feed_ids: vec![PriceFeedId(1), PriceFeedId(2)],
63+
price_feed_ids: Some(vec![PriceFeedId(1), PriceFeedId(2)]),
64+
symbols: None,
6465
properties: vec![
6566
PriceFeedProperty::Price,
6667
PriceFeedProperty::Exponent,
@@ -72,15 +73,20 @@ async fn main() -> anyhow::Result<()> {
7273
json_binary_encoding: JsonBinaryEncoding::Base64,
7374
parsed: true,
7475
channel: Channel::FixedRate(FixedRate::RATE_200_MS),
75-
ignore_invalid_feed_ids: false,
76+
ignore_invalid_feeds: false,
7677
})
7778
.expect("invalid subscription params"),
7879
},
79-
// Example subscription: binary feed targeting Solana and EVM
80+
// Example subscription: binary feed targeting Solana and EVM, specified by price feed symbols
8081
SubscribeRequest {
8182
subscription_id: SubscriptionId(2),
8283
params: SubscriptionParams::new(SubscriptionParamsRepr {
83-
price_feed_ids: vec![PriceFeedId(3), PriceFeedId(4)],
84+
price_feed_ids: None,
85+
symbols: Some(vec![
86+
"Crypto.BTC/USD".to_string(),
87+
"Crypto.ETH/USD".to_string(),
88+
"Crypto.PYTH/USD".to_string(),
89+
]),
8490
properties: vec![
8591
PriceFeedProperty::Price,
8692
PriceFeedProperty::Exponent,
@@ -92,7 +98,7 @@ async fn main() -> anyhow::Result<()> {
9298
json_binary_encoding: JsonBinaryEncoding::Base64,
9399
parsed: false,
94100
channel: Channel::FixedRate(FixedRate::RATE_50_MS),
95-
ignore_invalid_feed_ids: false,
101+
ignore_invalid_feeds: false,
96102
})
97103
.expect("invalid subscription params"),
98104
},

lazer/sdk/rust/protocol/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-lazer-protocol"
3-
version = "0.14.0"
3+
version = "0.15.0"
44
edition = "2021"
55
description = "Pyth Lazer SDK - protocol types."
66
license = "Apache-2.0"

lazer/sdk/rust/protocol/src/api.rs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use crate::{
1717
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1818
#[serde(rename_all = "camelCase")]
1919
pub struct LatestPriceRequest {
20-
pub price_feed_ids: Vec<PriceFeedId>,
20+
pub price_feed_ids: Option<Vec<PriceFeedId>>,
21+
pub symbols: Option<Vec<String>>,
2122
pub properties: Vec<PriceFeedProperty>,
2223
// "chains" was renamed to "formats". "chains" is still supported for compatibility.
2324
#[serde(alias = "chains")]
@@ -35,7 +36,9 @@ pub struct LatestPriceRequest {
3536
#[serde(rename_all = "camelCase")]
3637
pub struct PriceRequest {
3738
pub timestamp: TimestampUs,
38-
pub price_feed_ids: Vec<PriceFeedId>,
39+
// Either price feed ids or symbols must be specified.
40+
pub price_feed_ids: Option<Vec<PriceFeedId>>,
41+
pub symbols: Option<Vec<String>>,
3942
pub properties: Vec<PriceFeedProperty>,
4043
pub formats: Vec<Format>,
4144
#[serde(default)]
@@ -181,7 +184,9 @@ impl<'de> Deserialize<'de> for Channel {
181184
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
182185
#[serde(rename_all = "camelCase")]
183186
pub struct SubscriptionParamsRepr {
184-
pub price_feed_ids: Vec<PriceFeedId>,
187+
// Either price feed ids or symbols must be specified.
188+
pub price_feed_ids: Option<Vec<PriceFeedId>>,
189+
pub symbols: Option<Vec<String>>,
185190
pub properties: Vec<PriceFeedProperty>,
186191
// "chains" was renamed to "formats". "chains" is still supported for compatibility.
187192
#[serde(alias = "chains")]
@@ -195,8 +200,9 @@ pub struct SubscriptionParamsRepr {
195200
#[serde(default = "default_parsed")]
196201
pub parsed: bool,
197202
pub channel: Channel,
198-
#[serde(default)]
199-
pub ignore_invalid_feed_ids: bool,
203+
// "ignoreInvalidFeedIds" was renamed to "ignoreInvalidFeeds". "ignoreInvalidFeedIds" is still supported for compatibility.
204+
#[serde(default, alias = "ignoreInvalidFeedIds")]
205+
pub ignore_invalid_feeds: bool,
200206
}
201207

202208
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
@@ -215,12 +221,31 @@ impl<'de> Deserialize<'de> for SubscriptionParams {
215221

216222
impl SubscriptionParams {
217223
pub fn new(value: SubscriptionParamsRepr) -> Result<Self, &'static str> {
218-
if value.price_feed_ids.is_empty() {
219-
return Err("no price feed ids specified");
224+
if value.price_feed_ids.is_none() && value.symbols.is_none() {
225+
return Err("either price feed ids or symbols must be specified");
220226
}
221-
if !value.price_feed_ids.iter().all_unique() {
222-
return Err("duplicate price feed ids specified");
227+
if value.price_feed_ids.is_some() && value.symbols.is_some() {
228+
return Err("either price feed ids or symbols must be specified, not both");
223229
}
230+
231+
if let Some(ref ids) = value.price_feed_ids {
232+
if ids.is_empty() {
233+
return Err("no price feed ids specified");
234+
}
235+
if !ids.iter().all_unique() {
236+
return Err("duplicate price feed ids specified");
237+
}
238+
}
239+
240+
if let Some(ref symbols) = value.symbols {
241+
if symbols.is_empty() {
242+
return Err("no symbols specified");
243+
}
244+
if !symbols.iter().all_unique() {
245+
return Err("duplicate symbols specified");
246+
}
247+
}
248+
224249
if !value.formats.iter().all_unique() {
225250
return Err("duplicate formats or chains specified");
226251
}

0 commit comments

Comments
 (0)