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    // More fields may be added later.
90}
91
92#[derive(Debug, Clone, Deserialize)]
93#[serde(rename_all = "kebab-case")]
94pub enum AssetClass {
95    Crypto,
96    Fx,
97    Equity,
98    Metal,
99    Rates,
100    Nav,
101    Commodity,
102    FundingRate,
103}
104
105impl AssetClass {
106    pub fn as_str(&self) -> &'static str {
107        match self {
108            AssetClass::Crypto => "crypto",
109            AssetClass::Fx => "fx",
110            AssetClass::Equity => "equity",
111            AssetClass::Metal => "metal",
112            AssetClass::Rates => "rates",
113            AssetClass::Nav => "nav",
114            AssetClass::Commodity => "commodity",
115            AssetClass::FundingRate => "funding-rate",
116        }
117    }
118}
119
120// Operation and coefficient for converting value to mantissa.
121enum ExponentFactor {
122    // mantissa = value * factor
123    Mul(i64),
124    // mantissa = value / factor
125    Div(i64),
126}
127
128impl ExponentFactor {
129    fn get(exponent: i16) -> Option<Self> {
130        if exponent >= 0 {
131            let exponent: u32 = exponent.try_into().ok()?;
132            Some(ExponentFactor::Div(10_i64.checked_pow(exponent)?))
133        } else {
134            let minus_exponent: u32 = exponent.checked_neg()?.try_into().ok()?;
135            Some(ExponentFactor::Mul(10_i64.checked_pow(minus_exponent)?))
136        }
137    }
138}
139
140#[test]
141fn magics_in_big_endian() {
142    use crate::{
143        binary_update::BINARY_UPDATE_FORMAT_MAGIC,
144        message::format_magics_le::{
145            EVM_FORMAT_MAGIC, JSON_FORMAT_MAGIC, LE_ECDSA_FORMAT_MAGIC, LE_UNSIGNED_FORMAT_MAGIC,
146            SOLANA_FORMAT_MAGIC,
147        },
148        payload::PAYLOAD_FORMAT_MAGIC,
149    };
150
151    // The values listed in this test can be used when reading the magic headers in BE format
152    // (e.g., on EVM).
153
154    assert_eq!(u32::swap_bytes(BINARY_UPDATE_FORMAT_MAGIC), 1937213467);
155    assert_eq!(u32::swap_bytes(PAYLOAD_FORMAT_MAGIC), 1976813459);
156
157    assert_eq!(u32::swap_bytes(SOLANA_FORMAT_MAGIC), 3103857282);
158    assert_eq!(u32::swap_bytes(JSON_FORMAT_MAGIC), 2584795844);
159    assert_eq!(u32::swap_bytes(EVM_FORMAT_MAGIC), 706910618);
160    assert_eq!(u32::swap_bytes(LE_ECDSA_FORMAT_MAGIC), 3837609805);
161    assert_eq!(u32::swap_bytes(LE_UNSIGNED_FORMAT_MAGIC), 206398297);
162
163    for magic in [
164        BINARY_UPDATE_FORMAT_MAGIC,
165        PAYLOAD_FORMAT_MAGIC,
166        SOLANA_FORMAT_MAGIC,
167        JSON_FORMAT_MAGIC,
168        EVM_FORMAT_MAGIC,
169        LE_ECDSA_FORMAT_MAGIC,
170        LE_UNSIGNED_FORMAT_MAGIC,
171    ] {
172        // Required to distinguish between byte orders.
173        assert_ne!(u32::swap_bytes(magic), magic);
174    }
175}