pyth_lazer_protocol/
lib.rs

1//! Lazer type definitions and utilities.
2
3/// Types describing Lazer HTTP and WebSocket APIs.
4pub mod api;
5/// Binary delivery format for WebSocket.
6pub mod binary_update;
7mod dynamic_value;
8mod feed_kind;
9/// Lazer Agent JSON-RPC API.
10pub mod jrpc;
11/// Types describing Lazer's verifiable messages containing signature and payload.
12pub mod message;
13/// Types describing Lazer's message payload.
14pub mod payload;
15mod price;
16/// Legacy Websocket API for publishers.
17pub mod publisher;
18mod rate;
19mod serde_price_as_i64;
20mod serde_str;
21mod symbol_state;
22/// Lazer's types for time representation.
23pub mod time;
24
25use derive_more::derive::{From, Into};
26use serde::{Deserialize, Serialize};
27use utoipa::ToSchema;
28
29pub use crate::{
30    dynamic_value::DynamicValue,
31    feed_kind::FeedKind,
32    price::{Price, PriceError},
33    rate::{Rate, RateError},
34    symbol_state::SymbolState,
35};
36
37#[derive(
38    Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, From, Into,
39)]
40pub struct AssetId(pub u32);
41
42#[derive(
43    Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, From, Into,
44)]
45pub struct PublisherId(pub u16);
46
47#[derive(
48    Debug,
49    Clone,
50    Copy,
51    PartialEq,
52    Eq,
53    Hash,
54    PartialOrd,
55    Ord,
56    Serialize,
57    Deserialize,
58    From,
59    Into,
60    ToSchema,
61)]
62#[schema(value_type = u32)]
63pub struct PriceFeedId(pub u32);
64
65#[derive(
66    Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, From, Into,
67)]
68pub struct ChannelId(pub u8);
69
70impl ChannelId {
71    pub const REAL_TIME: ChannelId = ChannelId(1);
72    pub const FIXED_RATE_50: ChannelId = ChannelId(2);
73    pub const FIXED_RATE_200: ChannelId = ChannelId(3);
74    pub const FIXED_RATE_1000: ChannelId = ChannelId(4);
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)]
78#[serde(rename_all = "camelCase")]
79pub enum PriceFeedProperty {
80    Price,
81    BestBidPrice,
82    BestAskPrice,
83    PublisherCount,
84    Exponent,
85    Confidence,
86    FundingRate,
87    FundingTimestamp,
88    FundingRateInterval,
89    MarketSession,
90    // More fields may be added later.
91}
92
93#[derive(Debug, Clone, Deserialize)]
94#[serde(rename_all = "kebab-case")]
95pub enum AssetClass {
96    Crypto,
97    Fx,
98    Equity,
99    Metal,
100    Rates,
101    Nav,
102    Commodity,
103    FundingRate,
104}
105
106impl AssetClass {
107    pub fn as_str(&self) -> &'static str {
108        match self {
109            AssetClass::Crypto => "crypto",
110            AssetClass::Fx => "fx",
111            AssetClass::Equity => "equity",
112            AssetClass::Metal => "metal",
113            AssetClass::Rates => "rates",
114            AssetClass::Nav => "nav",
115            AssetClass::Commodity => "commodity",
116            AssetClass::FundingRate => "funding-rate",
117        }
118    }
119}
120
121// Operation and coefficient for converting value to mantissa.
122enum ExponentFactor {
123    // mantissa = value * factor
124    Mul(i64),
125    // mantissa = value / factor
126    Div(i64),
127}
128
129impl ExponentFactor {
130    fn get(exponent: i16) -> Option<Self> {
131        if exponent >= 0 {
132            let exponent: u32 = exponent.try_into().ok()?;
133            Some(ExponentFactor::Div(10_i64.checked_pow(exponent)?))
134        } else {
135            let minus_exponent: u32 = exponent.checked_neg()?.try_into().ok()?;
136            Some(ExponentFactor::Mul(10_i64.checked_pow(minus_exponent)?))
137        }
138    }
139}
140
141#[test]
142fn magics_in_big_endian() {
143    use crate::{
144        binary_update::BINARY_UPDATE_FORMAT_MAGIC,
145        message::format_magics_le::{
146            EVM_FORMAT_MAGIC, JSON_FORMAT_MAGIC, LE_ECDSA_FORMAT_MAGIC, LE_UNSIGNED_FORMAT_MAGIC,
147            SOLANA_FORMAT_MAGIC,
148        },
149        payload::PAYLOAD_FORMAT_MAGIC,
150    };
151
152    // The values listed in this test can be used when reading the magic headers in BE format
153    // (e.g., on EVM).
154
155    assert_eq!(u32::swap_bytes(BINARY_UPDATE_FORMAT_MAGIC), 1937213467);
156    assert_eq!(u32::swap_bytes(PAYLOAD_FORMAT_MAGIC), 1976813459);
157
158    assert_eq!(u32::swap_bytes(SOLANA_FORMAT_MAGIC), 3103857282);
159    assert_eq!(u32::swap_bytes(JSON_FORMAT_MAGIC), 2584795844);
160    assert_eq!(u32::swap_bytes(EVM_FORMAT_MAGIC), 706910618);
161    assert_eq!(u32::swap_bytes(LE_ECDSA_FORMAT_MAGIC), 3837609805);
162    assert_eq!(u32::swap_bytes(LE_UNSIGNED_FORMAT_MAGIC), 206398297);
163
164    for magic in [
165        BINARY_UPDATE_FORMAT_MAGIC,
166        PAYLOAD_FORMAT_MAGIC,
167        SOLANA_FORMAT_MAGIC,
168        JSON_FORMAT_MAGIC,
169        EVM_FORMAT_MAGIC,
170        LE_ECDSA_FORMAT_MAGIC,
171        LE_UNSIGNED_FORMAT_MAGIC,
172    ] {
173        // Required to distinguish between byte orders.
174        assert_ne!(u32::swap_bytes(magic), magic);
175    }
176}