gmsol_utils/price/
mod.rs

1/// Decimal type for price.
2pub mod decimal;
3
4pub use self::decimal::{Decimal, DecimalError};
5use anchor_lang::prelude::*;
6
7pub use ruint::aliases::U192;
8
9/// [`U192`] number 10.
10pub const TEN: U192 = U192::from_limbs([10, 0, 0]);
11
12/// Price type.
13#[derive(Debug, AnchorSerialize, AnchorDeserialize, Clone, Copy, InitSpace)]
14pub struct Price {
15    /// Min Price.
16    pub min: Decimal,
17    /// Max Price.
18    pub max: Decimal,
19}
20
21fn get_power_bounds() -> &'static [U192; 20] {
22    const BOUNDS: [U192; 20] = [
23        U192::from_limbs([18446744073709551615, 18446744073709551615, 0]),
24        U192::from_limbs([18446744073709551606, 18446744073709551615, 9]),
25        U192::from_limbs([18446744073709551516, 18446744073709551615, 99]),
26        U192::from_limbs([18446744073709550616, 18446744073709551615, 999]),
27        U192::from_limbs([18446744073709541616, 18446744073709551615, 9999]),
28        U192::from_limbs([18446744073709451616, 18446744073709551615, 99999]),
29        U192::from_limbs([18446744073708551616, 18446744073709551615, 999999]),
30        U192::from_limbs([18446744073699551616, 18446744073709551615, 9999999]),
31        U192::from_limbs([18446744073609551616, 18446744073709551615, 99999999]),
32        U192::from_limbs([18446744072709551616, 18446744073709551615, 999999999]),
33        U192::from_limbs([18446744063709551616, 18446744073709551615, 9999999999]),
34        U192::from_limbs([18446743973709551616, 18446744073709551615, 99999999999]),
35        U192::from_limbs([18446743073709551616, 18446744073709551615, 999999999999]),
36        U192::from_limbs([18446734073709551616, 18446744073709551615, 9999999999999]),
37        U192::from_limbs([18446644073709551616, 18446744073709551615, 99999999999999]),
38        U192::from_limbs([18445744073709551616, 18446744073709551615, 999999999999999]),
39        U192::from_limbs([18436744073709551616, 18446744073709551615, 9999999999999999]),
40        U192::from_limbs([
41            18346744073709551616,
42            18446744073709551615,
43            99999999999999999,
44        ]),
45        U192::from_limbs([
46            17446744073709551616,
47            18446744073709551615,
48            999999999999999999,
49        ]),
50        U192::from_limbs([
51            8446744073709551616,
52            18446744073709551615,
53            9999999999999999999,
54        ]),
55    ];
56
57    &BOUNDS
58}
59
60/// Finds the minimum divisor decimals needed to convert a fixed-point number
61/// from [`U192`] storage to [`u128`] storage.
62pub fn find_divisor_decimals(num: &U192) -> u8 {
63    let bounds = get_power_bounds();
64
65    match bounds.binary_search(num) {
66        Ok(idx) | Err(idx) => idx as u8,
67    }
68}
69
70/// Convert to [`u128`] storage.
71pub fn convert_to_u128_storage(mut num: U192, decimals: u8) -> Option<(u128, u8)> {
72    let divisor_decimals = find_divisor_decimals(&num);
73
74    if divisor_decimals > decimals {
75        return None;
76    }
77
78    num /= TEN.pow(U192::from(divisor_decimals));
79
80    Some((num.try_into().unwrap(), decimals - divisor_decimals))
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_bounds() {
89        let bounds = get_power_bounds();
90
91        assert_eq!(bounds.len(), 20);
92        assert_eq!(u128::try_from(bounds[0]).unwrap(), u128::MAX);
93        assert!(bounds[19].checked_mul(U192::from(10)).is_none());
94
95        assert_eq!(find_divisor_decimals(&U192::from(u128::MAX)), 0);
96        assert_eq!(find_divisor_decimals(&U192::MAX), 20);
97    }
98
99    #[test]
100    fn test_convert_to_u128_storage() {
101        assert_eq!(
102            convert_to_u128_storage(U192::from(u128::MAX), 18),
103            Some((u128::MAX, 18))
104        );
105
106        assert_eq!(
107            convert_to_u128_storage(U192::from(u128::MAX) + U192::from(1), 18),
108            Some((34028236692093846346337460743176821145, 17))
109        );
110
111        assert_eq!(
112            convert_to_u128_storage(U192::MAX, 20),
113            Some((62771017353866807638357894232076664161, 0))
114        );
115
116        assert_eq!(
117            convert_to_u128_storage(
118                U192::from(u128::MAX)
119                    .checked_mul(U192::from(10).pow(U192::from(19)))
120                    .unwrap()
121                    - U192::from(11),
122                20
123            ),
124            Some((340282366920938463463374607431768211454, 1))
125        );
126        assert_eq!(
127            convert_to_u128_storage(
128                U192::from(u128::MAX)
129                    .checked_mul(U192::from(10).pow(U192::from(19)))
130                    .unwrap()
131                    + U192::from(1),
132                20
133            ),
134            Some((34028236692093846346337460743176821145, 0))
135        );
136
137        assert_eq!(
138            convert_to_u128_storage(
139                U192::from(u128::MAX)
140                    .checked_mul(U192::from(10).pow(U192::from(18)))
141                    .unwrap(),
142                18
143            ),
144            Some((340282366920938463463374607431768211455, 0))
145        );
146    }
147}