Skip to content

Conversation

tejasbadadare
Copy link
Contributor

Summary

Add types for output representations of the Metadata v3 API.

  • FeedResponseV3: Returned by the /v3/feeds APIs
  • AssetResponseV3: Returned by the /v3/assets APIs
  • Existing /v1/symbols API will continue to return the history_service::api::SymbolResponse from Lazer internals for the time being. In the future, this type should be unified with the duplicated one in the protocol crate (pyth_lazer_protocol::jrpc::SymbolMetadata, used by History client).

How has this been tested?

  • Current tests cover my changes
  • Added new tests
  • Manually tested the code

Copy link

vercel bot commented Oct 7, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
api-reference Ready Ready Preview Comment Oct 7, 2025 0:00am
component-library Ready Ready Preview Comment Oct 7, 2025 0:00am
developer-hub Ready Ready Preview Comment Oct 7, 2025 0:00am
entropy-explorer Ready Ready Preview Comment Oct 7, 2025 0:00am
insights Ready Ready Preview Comment Oct 7, 2025 0:00am
proposals Ready Ready Preview Comment Oct 7, 2025 0:00am
staking Ready Ready Preview Comment Oct 7, 2025 0:00am

/// Commodity
Commodity,
/// Funding rate
FundingRate,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really an asset class?

/// High-level asset class.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum AssetClass {
Copy link
Collaborator

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.

Copy link
Contributor

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.

/// Rates
Rates,
/// Net Asset Value
Nav,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also doesn't seem to be an asset class, it's a feed/instrument type.

/// 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,
Copy link
Collaborator

Choose a reason for hiding this comment

The 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)

/// CoinMarketCap asset identifier.
/// Example: `"123"`
#[serde(skip_serializing_if = "Option::is_none")]
pub cmc_id: Option<String>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder whether you considered @jayantk suggestion on having a nested struct as "external mappings". It's probably more difficult on the DB layer.

pub feed_expiry: Option<String>,
/// The nature of the data produced by the feed.
/// Examples: `"price"`, `"fundingRate"`
pub feed_kind: FeedKind,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm so we do have a feedkind and an instrument type. I wonder whether we can merge them.

/// 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>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a datetime type or an integer based timestamp (i bet we should have something similar in our code)

/// Example: `"stablecoin"`
#[serde(skip_serializing_if = "Option::is_none")]
pub subclass: Option<String>,
/// Primary or canonical listing exchange, when applicable.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, what if there are multiple?
i suggest renaming the field to primary_exchange or something similar here. not sure listing_exchange is clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants