use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriceData {
pub price: String,
pub conf: String,
pub expo: i32,
pub publish_time: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmaPrice {
pub price: String,
pub conf: String,
pub expo: i32,
pub publish_time: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParsedPriceFeed {
pub id: String,
pub price: PriceData,
#[serde(default)]
pub ema_price: Option<EmaPrice>,
#[serde(default)]
pub metadata: Option<PriceUpdateMetadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriceUpdateMetadata {
#[serde(default)]
pub slot: Option<u64>,
#[serde(default)]
pub proof_available_time: Option<i64>,
#[serde(default)]
pub prev_publish_time: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LatestPriceResponse {
pub binary: BinaryData,
pub parsed: Vec<ParsedPriceFeed>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BinaryData {
pub encoding: String,
pub data: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriceFeedId {
pub id: String,
#[serde(default)]
pub attributes: PriceFeedAttributes,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PriceFeedAttributes {
#[serde(default)]
pub asset_type: Option<String>,
#[serde(default)]
pub base: Option<String>,
#[serde(default)]
pub quote: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub generic_symbol: Option<String>,
#[serde(default)]
pub symbol: Option<String>,
}
impl ParsedPriceFeed {
#[must_use]
pub fn price_f64(&self) -> Option<f64> {
let price: f64 = self.price.price.parse().ok()?;
Some(price * 10f64.powi(self.price.expo))
}
#[must_use]
pub fn ema_price_f64(&self) -> Option<f64> {
let ema = self.ema_price.as_ref()?;
let price: f64 = ema.price.parse().ok()?;
Some(price * 10f64.powi(ema.expo))
}
#[must_use]
pub fn confidence_f64(&self) -> Option<f64> {
let conf: f64 = self.price.conf.parse().ok()?;
Some(conf * 10f64.powi(self.price.expo))
}
#[must_use]
pub fn ema_confidence_f64(&self) -> Option<f64> {
let ema = self.ema_price.as_ref()?;
let conf: f64 = ema.conf.parse().ok()?;
Some(conf * 10f64.powi(ema.expo))
}
#[must_use]
pub fn is_stale(&self, max_age_secs: i64) -> bool {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0);
now - self.price.publish_time > max_age_secs
}
}