Skip to main content

gmsol_sdk/utils/
amount.rs

1use std::{fmt, str::FromStr};
2
3use crate::{
4    constants::{MARKET_DECIMALS, MARKET_TOKEN_DECIMALS},
5    utils::{decimal_to_amount, decimal_to_value},
6};
7use rust_decimal::Decimal;
8
9use super::{
10    decimal_to_signed_value, signed_value_to_decimal, unsigned_amount_to_decimal,
11    unsigned_fixed_to_decimal, unsigned_value_to_decimal,
12};
13
14const LAMPORT_DECIMALS: u8 = 9;
15
16/// Amount in lamports.
17#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
19pub struct Lamport(#[cfg_attr(serde, serde(with = "rust_decimal::serde::str"))] pub Decimal);
20
21impl fmt::Display for Lamport {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        write!(f, "{}", self.0)
24    }
25}
26
27impl FromStr for Lamport {
28    type Err = <Decimal as FromStr>::Err;
29
30    fn from_str(s: &str) -> Result<Self, Self::Err> {
31        Ok(Self(s.parse()?))
32    }
33}
34
35impl Lamport {
36    /// Zero.
37    pub const ZERO: Self = Self(Decimal::ZERO);
38
39    /// Convert to `u64`
40    pub fn to_u64(&self) -> crate::Result<u64> {
41        decimal_to_amount(self.0, LAMPORT_DECIMALS)
42    }
43
44    /// Create from `u64`.
45    pub fn from_u64(amount: u64) -> Self {
46        Self(unsigned_amount_to_decimal(amount, LAMPORT_DECIMALS).normalize())
47    }
48
49    /// Returns whether the amount is zero.
50    pub const fn is_zero(&self) -> bool {
51        self.0.is_zero()
52    }
53}
54
55/// Market token amount.
56#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
57#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
58pub struct GmAmount(#[cfg_attr(serde, serde(with = "rust_decimal::serde::str"))] pub Decimal);
59
60impl fmt::Display for GmAmount {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        write!(f, "{}", self.0)
63    }
64}
65
66impl FromStr for GmAmount {
67    type Err = <Decimal as FromStr>::Err;
68
69    fn from_str(s: &str) -> Result<Self, Self::Err> {
70        Ok(Self(s.parse()?))
71    }
72}
73
74impl GmAmount {
75    /// Zero.
76    pub const ZERO: Self = Self(Decimal::ZERO);
77
78    /// Convert to `u64`
79    pub fn to_u64(&self) -> crate::Result<u64> {
80        decimal_to_amount(self.0, MARKET_TOKEN_DECIMALS)
81    }
82
83    /// Create from `u64`.
84    pub fn from_u64(amount: u64) -> Self {
85        Self(unsigned_amount_to_decimal(amount, MARKET_TOKEN_DECIMALS).normalize())
86    }
87
88    /// Returns whether the amount is zero.
89    pub const fn is_zero(&self) -> bool {
90        self.0.is_zero()
91    }
92}
93
94/// A general-purpose token amount.
95#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
96#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
97pub struct Amount(#[cfg_attr(serde, serde(with = "rust_decimal::serde::str"))] pub Decimal);
98
99impl fmt::Display for Amount {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        write!(f, "{}", self.0)
102    }
103}
104
105impl FromStr for Amount {
106    type Err = <Decimal as FromStr>::Err;
107
108    fn from_str(s: &str) -> Result<Self, Self::Err> {
109        Ok(Self(s.parse()?))
110    }
111}
112
113impl Amount {
114    /// Zero.
115    pub const ZERO: Self = Self(Decimal::ZERO);
116
117    /// Convert to `u64`.
118    pub fn to_u64(&self, decimals: u8) -> crate::Result<u64> {
119        decimal_to_amount(self.0, decimals)
120    }
121
122    /// Create from `u64`.
123    pub fn from_u64(amount: u64, decimals: u8) -> Self {
124        Self(unsigned_amount_to_decimal(amount, decimals).normalize())
125    }
126
127    /// Convert to `u128`.
128    pub fn to_u128(&self, decimals: u8) -> crate::Result<u128> {
129        decimal_to_value(self.0, decimals)
130    }
131
132    /// Create from `u128`.
133    pub fn from_u128(amount: u128, decimals: u8) -> crate::Result<Self> {
134        Ok(Self(
135            unsigned_fixed_to_decimal(amount, decimals)
136                .ok_or_else(|| crate::Error::custom("amount exceeds the maximum value"))?
137                .normalize(),
138        ))
139    }
140
141    /// Returns whether the amount is zero.
142    pub const fn is_zero(&self) -> bool {
143        self.0.is_zero()
144    }
145}
146
147/// A value with [`MARKET_DECIMALS`] decimals.
148#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
149#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
150pub struct Value(#[cfg_attr(serde, serde(with = "rust_decimal::serde::str"))] pub Decimal);
151
152impl fmt::Display for Value {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(f, "{}", self.0)
155    }
156}
157
158impl FromStr for Value {
159    type Err = <Decimal as FromStr>::Err;
160
161    fn from_str(s: &str) -> Result<Self, Self::Err> {
162        Ok(Self(s.parse()?))
163    }
164}
165
166impl Value {
167    /// Zero.
168    pub const ZERO: Self = Self(Decimal::ZERO);
169
170    /// Convert to `u128`.
171    pub fn to_u128(&self) -> crate::Result<u128> {
172        decimal_to_value(self.0, MARKET_DECIMALS)
173    }
174
175    /// Convert to `i128`.
176    pub fn to_i128(&self) -> i128 {
177        decimal_to_signed_value(self.0, MARKET_DECIMALS)
178    }
179
180    /// Create from `i128`.
181    pub fn from_i128(value: i128) -> Self {
182        Self(signed_value_to_decimal(value).normalize())
183    }
184
185    /// Create from `u128`.
186    pub fn from_u128(value: u128) -> Self {
187        Self(unsigned_value_to_decimal(value).normalize())
188    }
189
190    /// Returns whether the amount is zero.
191    pub const fn is_zero(&self) -> bool {
192        self.0.is_zero()
193    }
194}
195
196impl From<u128> for Value {
197    fn from(value: u128) -> Self {
198        Self::from_u128(value)
199    }
200}