-
Notifications
You must be signed in to change notification settings - Fork 311
feat(lazer-protocol): add Metadata V3 response types #3111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
438a206
ebf5caf
05e2dba
ead5853
6dd6551
c2c1de8
61906e1
103690f
7bf6d87
416bc1c
2896662
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| //! Types describing Lazer's metadata APIs. | ||
|
|
||
| use crate::FeedKind; | ||
| use crate::{symbol_state::SymbolState, PriceFeedId}; | ||
| use serde::{Deserialize, Serialize}; | ||
|
|
||
| /// The pricing context or type of instrument for a feed. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
| #[serde(rename_all = "lowercase")] | ||
| pub enum InstrumentType { | ||
| /// Spot price | ||
| Spot, | ||
| /// Redemption rate | ||
| #[serde(rename = "redemptionrate")] | ||
| RedemptionRate, | ||
| /// Funding rate | ||
| #[serde(rename = "fundingrate")] | ||
| FundingRate, | ||
| /// Future price | ||
| Future, | ||
| /// Net Asset Value | ||
| Nav, | ||
| /// Time-weighted average price | ||
| Twap, | ||
| } | ||
|
|
||
| /// High-level asset class. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
| #[serde(rename_all = "kebab-case")] | ||
| pub enum AssetClass { | ||
| /// Cryptocurrency | ||
| Crypto, | ||
| /// Foreign exchange | ||
| Fx, | ||
| /// Equity | ||
| Equity, | ||
| /// Metal | ||
| Metal, | ||
| /// Rates | ||
| Rates, | ||
| /// Net Asset Value | ||
| Nav, | ||
tejasbadadare marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// Commodity | ||
| Commodity, | ||
| /// Funding rate | ||
| FundingRate, | ||
|
||
| } | ||
|
|
||
| /// Feed metadata as returned by the v3 metadata API. | ||
| #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
| pub struct FeedResponseV3 { | ||
| /// Unique integer identifier for a feed. Known as `pyth_lazer_id` in V1 API. | ||
| /// Example: `1` | ||
| pub id: PriceFeedId, | ||
| /// Short feed name. | ||
| /// Example: `"Bitcoin / US Dollar"` | ||
| pub name: String, | ||
| /// Unique human-readable identifier for a feed. | ||
| /// Format: `source.instrument_type.base/quote` | ||
| /// Examples: `"pyth.spot.btc/usd"`, `"pyth.redemptionrate.alp/usd"`, `"binance.fundingrate.btc/usdt"`, `"pyth.future.emz5/usd"` | ||
| pub symbol: String, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i recommend opting for a specific type with validation here to ensure it's correct. q: what if the asset has no quote asset? (such as rates)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A type with validation to enforce the string format is a good idea.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay caught up with @YaserJazouane on this and yep we should make the quote asset optional. There are cases like yields, indices, fundingrates that aren't quoted in any currency. Our existing funding rate example is denominated in USD which is incorrect. tldr:
|
||
| /// Description of the feed pair. | ||
| /// Example: `"Pyth Network Aggregate Price for spot BTC/USD"` | ||
| pub description: String, | ||
| /// The Asset ID of the base asset. | ||
| /// Example: `"BTC"` | ||
| pub base_asset_id: String, | ||
| /// The Asset ID of the quote asset. | ||
| /// Example: `"USD"` | ||
| pub quote_asset_id: String, | ||
| /// The pricing context. | ||
| /// Example: `"spot"` | ||
| pub instrument_type: InstrumentType, | ||
| /// Aggregator or producer of the prices. | ||
| /// Examples: `"pyth"`, `"binance"` | ||
| pub source: String, | ||
| /// The trading schedule of the feed's market, in Pythnet format. | ||
| /// Example: `"America/New_York;O,O,O,O,O,O,O;"` | ||
| pub schedule: String, | ||
| /// Power-of-ten exponent. Scale the `price` mantissa value by `10^exponent` to get the decimal representation. | ||
| /// Example: `-8` | ||
| pub exponent: i32, | ||
| /// Funding rate interval. Only applies to feeds with instrument type `funding_rate`. | ||
| /// Example: `10` | ||
| pub update_interval_seconds: i32, | ||
| /// The minimum number of publishers contributing component prices to the aggregate price. | ||
| /// Example: `3` | ||
| pub min_publishers: i32, | ||
| /// Status of the feed. | ||
| /// Example: `"active"` | ||
| pub state: SymbolState, | ||
| /// High-level asset class. One of crypto, fx, equity, metal, rates, nav, commodity, funding-rate. | ||
| /// Example: `"crypto"` | ||
| pub asset_type: AssetClass, | ||
| /// CoinMarketCap asset identifier. | ||
| /// Example: `"123"` | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub cmc_id: Option<String>, | ||
|
||
| /// Pythnet feed identifier. 32 bytes, represented in hex. | ||
| /// Example: `"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"` | ||
| pub pythnet_id: String, | ||
| /// Nasdaq symbol identifier. | ||
| /// Example: `"ADSK"` | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub nasdaq_symbol: Option<String>, | ||
| /// ISO datetime after which the feed will no longer produce prices because the underlying market has expired. | ||
| /// Example: `"2025-10-03T11:08:10.089998603Z"` | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub feed_expiry: Option<String>, | ||
tejasbadadare marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// The nature of the data produced by the feed. | ||
| /// Examples: `"price"`, `"fundingRate"` | ||
| pub feed_kind: FeedKind, | ||
|
||
| } | ||
|
|
||
| /// Asset metadata as returned by the v3 metadata API. | ||
| #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
| pub struct AssetResponseV3 { | ||
| /// Unique identifier for an asset. | ||
| /// Example: `"BTC"` | ||
| pub id: String, | ||
| /// A short, human-readable code that identifies an asset. Not guaranteed to be unique. | ||
| /// Example: `"BTC"` | ||
| pub ticker: String, | ||
| /// Full human-readable name of the asset. | ||
| /// Example: `"Bitcoin"` | ||
| pub full_name: String, | ||
| /// High-level asset class. | ||
| /// Example: `"crypto"` | ||
| pub class: AssetClass, | ||
| /// More granular categorization within class. | ||
| /// Example: `"stablecoin"` | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub subclass: Option<String>, | ||
| /// Primary or canonical listing exchange, when applicable. | ||
tejasbadadare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// Example: `"NASDAQ"` | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub listing_exchange: Option<String>, | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the reasons for opting in a dynamic metadata was to not go through a code change when new asset classes are added to the system. I know that users (on both sides) rely on these, and that's probably why you opted for explicit definition here. But if that's the case, you might actually remove any dynamic field and make everything very explicit. Being in the middle (some explicit metadata, some implicit dynamic) is probably worse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should stick with our decision and use fully dynamic metadata in the protocols. In Rust that would be
BTreeMap<String, serde_value::Value>. We can revisit it later if we feel like the metadata structure is very stable and future-proof, but I doubt that it will happen soon.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah my main goal in adding these explicit types is to ensure end users can depend on a stable API contract across different versions. I.e. the different types like the existing
SymbolResponseand the newFeedResponseV3can handle the differences between v1 and v3 representations derived from the same internal dynamic metadata representation.