gmsol_store/states/oracle/
price_map.rs

1use anchor_lang::prelude::*;
2use gmsol_utils::price::Decimal;
3
4use crate::{utils::pubkey::to_bytes, CoreError};
5
6/// Zero-copy price structure for storing min max prices.
7#[zero_copy]
8#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
9pub struct SmallPrices {
10    decimal_multipler: u8,
11    flags: u8,
12    #[cfg_attr(feature = "debug", debug(skip))]
13    padding_0: [u8; 2],
14    min: u32,
15    max: u32,
16}
17
18impl Default for SmallPrices {
19    fn default() -> Self {
20        bytemuck::Zeroable::zeroed()
21    }
22}
23
24impl SmallPrices {
25    const SYNTHETIC_FLAGS: u8 = u8::MAX;
26
27    /// Get min price.
28    pub fn min(&self) -> Decimal {
29        Decimal {
30            value: self.min,
31            decimal_multiplier: self.decimal_multipler,
32        }
33    }
34
35    /// Get max price.
36    pub fn max(&self) -> Decimal {
37        Decimal {
38            value: self.max,
39            decimal_multiplier: self.decimal_multipler,
40        }
41    }
42
43    pub(crate) fn from_price(price: &gmsol_utils::Price, is_synthetic: bool) -> Result<Self> {
44        // Validate price data.
45        require_eq!(
46            price.min.decimal_multiplier,
47            price.max.decimal_multiplier,
48            CoreError::InvalidArgument
49        );
50        require_neq!(price.min.value, 0, CoreError::InvalidArgument);
51        require_gte!(price.max.value, price.min.value, CoreError::InvalidArgument);
52
53        let flags = if is_synthetic {
54            Self::SYNTHETIC_FLAGS
55        } else {
56            0
57        };
58
59        Ok(SmallPrices {
60            decimal_multipler: price.min.decimal_multiplier,
61            flags,
62            padding_0: [0; 2],
63            min: price.min.value,
64            max: price.max.value,
65        })
66    }
67
68    /// Returns whether the token is synthetic.
69    pub fn is_synthetic(&self) -> bool {
70        self.flags == Self::SYNTHETIC_FLAGS
71    }
72
73    /// Convert to [`Price`](gmsol_utils::Price).
74    pub fn to_price(&self) -> Result<gmsol_utils::Price> {
75        Ok(gmsol_utils::Price {
76            min: self.min(),
77            max: self.max(),
78        })
79    }
80}
81
82const MAX_TOKENS: usize = 512;
83
84gmsol_utils::fixed_map!(PriceMap, Pubkey, to_bytes, SmallPrices, MAX_TOKENS, 0);
85
86impl PriceMap {
87    /// Max tokens.
88    pub const MAX_TOKENS: usize = MAX_TOKENS;
89
90    pub(super) fn set(
91        &mut self,
92        token: &Pubkey,
93        price: gmsol_utils::Price,
94        is_synthetic: bool,
95    ) -> Result<()> {
96        self.insert(token, SmallPrices::from_price(&price, is_synthetic)?);
97        Ok(())
98    }
99}