Skip to content

Commit ead5853

Browse files
committed
feat(lazer-protocol): use Strings instead of enums in the public API, make SymbolV3.quote optional
1 parent 05e2dba commit ead5853

File tree

2 files changed

+137
-233
lines changed

2 files changed

+137
-233
lines changed

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

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,20 @@ use crate::time::TimestampUs;
44
use crate::FeedKind;
55
use crate::{symbol_state::SymbolState, PriceFeedId, SymbolV3};
66
use serde::{Deserialize, Serialize};
7-
use strum::{Display, EnumString};
87

98
/// The pricing context or type of instrument for a feed.
10-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
9+
/// This is an internal type and should not be used by clients as it is non-exhaustive.
10+
/// The API response can evolve to contain additional variants that are not listed here.
11+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1112
#[serde(rename_all = "lowercase")]
12-
#[strum(serialize_all = "lowercase")]
1313
pub enum InstrumentType {
1414
/// Spot price
1515
Spot,
1616
/// Redemption rate
1717
#[serde(rename = "redemptionrate")]
18-
#[strum(serialize = "redemptionrate")]
1918
RedemptionRate,
2019
/// Funding rate
2120
#[serde(rename = "fundingrate")]
22-
#[strum(serialize = "fundingrate")]
2321
FundingRate,
2422
/// Future price
2523
Future,
@@ -30,6 +28,8 @@ pub enum InstrumentType {
3028
}
3129

3230
/// High-level asset class.
31+
/// This is an internal type and should not be used by clients as it is non-exhaustive.
32+
/// The API response can evolve to contain additional variants that are not listed here.
3333
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
3434
#[serde(rename_all = "kebab-case")]
3535
pub enum AssetClass {
@@ -43,12 +43,8 @@ pub enum AssetClass {
4343
Metal,
4444
/// Rates
4545
Rates,
46-
/// Net Asset Value
47-
Nav,
4846
/// Commodity
4947
Commodity,
50-
/// Funding rate
51-
FundingRate,
5248
}
5349

5450
/// Feed metadata as returned by the v3 metadata API.
@@ -73,9 +69,9 @@ pub struct FeedResponseV3 {
7369
/// The Asset ID of the quote asset.
7470
/// Example: `"USD"`
7571
pub quote_asset_id: String,
76-
/// The pricing context.
72+
/// The pricing context. Should be one of the values in the InstrumentType enum.
7773
/// Example: `"spot"`
78-
pub instrument_type: InstrumentType,
74+
pub instrument_type: String,
7975
/// Aggregator or producer of the prices.
8076
/// Examples: `"pyth"`, `"binance"`
8177
pub source: String,
@@ -95,8 +91,9 @@ pub struct FeedResponseV3 {
9591
/// Example: `"active"`
9692
pub state: SymbolState,
9793
/// High-level asset class. One of crypto, fx, equity, metal, rates, nav, commodity, funding-rate.
94+
/// Should be one of the values in the AssetClass enum.
9895
/// Example: `"crypto"`
99-
pub asset_type: AssetClass,
96+
pub asset_type: String,
10097
/// CoinMarketCap asset identifier.
10198
/// Example: `"123"`
10299
#[serde(skip_serializing_if = "Option::is_none")]
@@ -131,7 +128,7 @@ pub struct AssetResponseV3 {
131128
pub full_name: String,
132129
/// High-level asset class.
133130
/// Example: `"crypto"`
134-
pub class: AssetClass,
131+
pub class: String,
135132
/// More granular categorization within class.
136133
/// Example: `"stablecoin"`
137134
#[serde(skip_serializing_if = "Option::is_none")]
@@ -146,37 +143,15 @@ pub struct AssetResponseV3 {
146143
mod tests {
147144
use super::*;
148145

149-
#[test]
150-
fn test_instrument_type_roundtrip() {
151-
let types = vec![
152-
InstrumentType::Spot,
153-
InstrumentType::RedemptionRate,
154-
InstrumentType::FundingRate,
155-
InstrumentType::Future,
156-
InstrumentType::Nav,
157-
InstrumentType::Twap,
158-
];
159-
160-
for instrument_type in types {
161-
let string_repr = instrument_type.to_string();
162-
let parsed = string_repr.parse::<InstrumentType>().unwrap();
163-
assert_eq!(parsed, instrument_type);
164-
}
165-
166-
// Test invalid values
167-
assert!("invalid".parse::<InstrumentType>().is_err());
168-
assert!("SPOT".parse::<InstrumentType>().is_err()); // case sensitive
169-
}
170-
171146
#[test]
172147
fn test_feed_response_v3_roundtrip() {
173148
use crate::{symbol_state::SymbolState, FeedKind, PriceFeedId};
174149

175150
let symbol = SymbolV3::new(
176151
"pyth".to_string(),
177-
InstrumentType::Spot,
152+
"spot".to_string(),
178153
"btc".to_string(),
179-
"usd".to_string(),
154+
Some("usd".to_string()),
180155
);
181156

182157
let feed_response = FeedResponseV3 {
@@ -186,14 +161,14 @@ mod tests {
186161
description: "Pyth Network Aggregate Price for spot BTC/USD".to_string(),
187162
base_asset_id: "BTC".to_string(),
188163
quote_asset_id: "USD".to_string(),
189-
instrument_type: InstrumentType::Spot,
164+
instrument_type: "spot".to_string(),
190165
source: "pyth".to_string(),
191166
schedule: "America/New_York;O,O,O,O,O,O,O;".to_string(),
192167
exponent: -8,
193168
update_interval_seconds: 10,
194169
min_publishers: 3,
195170
state: SymbolState::Stable,
196-
asset_type: AssetClass::Crypto,
171+
asset_type: "crypto".to_string(),
197172
cmc_id: Some("1".to_string()),
198173
pythnet_id: "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
199174
.to_string(),
@@ -212,9 +187,9 @@ mod tests {
212187
serde_json::from_str(&json).expect("Failed to deserialize FeedResponseV3");
213188
assert_eq!(deserialized.symbol.as_string(), "pyth.spot.btc/usd");
214189
assert_eq!(deserialized.symbol.source, "pyth");
215-
assert_eq!(deserialized.symbol.instrument_type, InstrumentType::Spot);
190+
assert_eq!(deserialized.symbol.instrument_type, "spot");
216191
assert_eq!(deserialized.symbol.base, "btc");
217-
assert_eq!(deserialized.symbol.quote, "usd");
192+
assert_eq!(deserialized.symbol.quote, Some("usd".to_string()));
218193

219194
// Ensure the entire structure matches
220195
assert_eq!(deserialized, feed_response);

0 commit comments

Comments
 (0)