Skip to main content

cosmwasm_common_library/
bigdecimal.rs

1use crate::biginteger::BigInteger;
2use core::fmt::{Display, Formatter};
3use core::str::FromStr;
4use cosmwasm_schema::cw_serde;
5use cosmwasm_std::{Decimal256, StdError, Uint128, Uint256};
6use std::iter::Sum;
7use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub, SubAssign};
8
9#[cw_serde]
10#[derive(Copy, Default, Ord, PartialOrd, Eq)]
11pub struct BigDecimal(pub Decimal256);
12
13impl BigDecimal {
14    pub const MAX: Self = Self(Decimal256::MAX);
15    pub const MIN: Self = Self(Decimal256::MIN);
16
17    pub fn new(bigint: BigInteger) -> Self {
18        Self(Decimal256::new(bigint.0))
19    }
20
21    pub fn from(bigint: BigInteger, decimals: u32) -> Self {
22        Self(Decimal256::from_ratio(
23            bigint.0,
24            Uint128::from(10u64).pow(decimals),
25        ))
26    }
27
28    pub fn is_zero(&self) -> bool {
29        self.0.is_zero()
30    }
31
32    pub fn percent(x: u64) -> BigDecimal {
33        Self(Decimal256::percent(x))
34    }
35
36    pub fn zero() -> Self {
37        Self(Decimal256::zero())
38    }
39
40    pub fn one() -> Self {
41        Self(Decimal256::one())
42    }
43
44    pub fn from_ratio(numerator: impl Into<Uint256>, denominator: impl Into<Uint256>) -> Self {
45        Self(Decimal256::from_ratio(numerator, denominator))
46    }
47
48    pub fn saturating_sub(&self, rhs: Self) -> Self {
49        Self(Decimal256::saturating_sub(self.0, rhs.0))
50    }
51
52    pub fn scale_up(&self, decimals: u32) -> BigInteger {
53        BigInteger((self.0 * Decimal256::from_ratio(10u128.pow(decimals), 1u128)).to_uint_floor())
54    }
55
56    pub fn move_point_right(&self, decimals: u32) -> BigDecimal {
57        *self * BigDecimal::from_ratio(10u128.pow(decimals), 1u128)
58    }
59
60    pub fn move_point_left(&self, decimals: u32) -> BigDecimal {
61        *self / BigDecimal::from_ratio(10u128.pow(decimals), 1u128)
62    }
63
64    pub fn is_ratio(&self) -> bool {
65        *self >= BigDecimal::zero() && *self <= BigDecimal::one()
66    }
67
68    pub fn from_be_bytes(bytes: [u8; 32]) -> Self {
69        Self(Decimal256::new(Uint256::from_be_bytes(bytes)))
70    }
71
72    pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
73        Self(Decimal256::new(Uint256::from_le_bytes(bytes)))
74    }
75
76    pub fn to_be_bytes(&self) -> [u8; 32] {
77        self.0.atomics().to_be_bytes()
78    }
79
80    pub fn to_le_bytes(&self) -> [u8; 32] {
81        self.0.atomics().to_le_bytes()
82    }
83}
84
85impl Sub<BigDecimal> for BigDecimal {
86    type Output = BigDecimal;
87
88    fn sub(self, rhs: BigDecimal) -> Self::Output {
89        Self(self.0 - rhs.0)
90    }
91}
92
93impl Add<BigDecimal> for BigDecimal {
94    type Output = BigDecimal;
95
96    fn add(self, rhs: BigDecimal) -> Self::Output {
97        Self(self.0 + rhs.0)
98    }
99}
100
101impl Div<BigDecimal> for BigDecimal {
102    type Output = BigDecimal;
103
104    fn div(self, rhs: BigDecimal) -> Self::Output {
105        BigDecimal(self.0 / rhs.0)
106    }
107}
108
109impl Div<BigInteger> for BigDecimal {
110    type Output = BigDecimal;
111
112    fn div(self, rhs: BigInteger) -> Self::Output {
113        self / BigDecimal::from(rhs, 0)
114    }
115}
116
117impl Mul<BigDecimal> for BigDecimal {
118    type Output = BigDecimal;
119
120    fn mul(self, rhs: BigDecimal) -> Self::Output {
121        Self(self.0 * rhs.0)
122    }
123}
124
125impl Mul<BigInteger> for BigDecimal {
126    type Output = BigDecimal;
127
128    fn mul(self, rhs: BigInteger) -> Self::Output {
129        self * BigDecimal::from(rhs, 0)
130    }
131}
132
133impl AddAssign for BigDecimal {
134    fn add_assign(&mut self, rhs: Self) {
135        self.0 += rhs.0;
136    }
137}
138
139impl SubAssign for BigDecimal {
140    fn sub_assign(&mut self, rhs: Self) {
141        self.0 -= rhs.0;
142    }
143}
144
145impl MulAssign for BigDecimal {
146    fn mul_assign(&mut self, rhs: Self) {
147        self.0 *= rhs.0;
148    }
149}
150
151impl Display for BigDecimal {
152    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
153        std::fmt::Display::fmt(&self.0, f)
154    }
155}
156
157impl FromStr for BigDecimal {
158    type Err = StdError;
159
160    fn from_str(s: &str) -> Result<Self, Self::Err> {
161        const DECIMAL_FRACTIONAL: Uint256 = // 1*10**18
162            Uint256::new(1_000_000_000_000_000_000);
163        let mut parts_iter = s.split('.');
164
165        let whole_part = parts_iter.next().unwrap(); // split always returns at least one element
166        let whole = whole_part
167            .parse::<Uint256>()
168            .map_err(|_| StdError::msg("Error parsing whole"))?;
169        let mut atomics = whole
170            .checked_mul(DECIMAL_FRACTIONAL)
171            .map_err(|_| StdError::msg("Value too big"))?;
172
173        if let Some(fractional_part) = parts_iter.next() {
174            let fractional = fractional_part
175                .parse::<Uint256>()
176                .map_err(|_| StdError::msg("Error parsing fractional"))?;
177            let exp = (Decimal256::DECIMAL_PLACES.checked_sub(fractional_part.len() as u32))
178                .ok_or_else(|| {
179                    StdError::msg(format!(
180                        "Cannot parse more than {} fractional digits",
181                        Decimal256::DECIMAL_PLACES
182                    ))
183                })?;
184            let fractional_factor = Uint256::from(10u128).pow(exp);
185            atomics = atomics
186                .checked_add(
187                    // The inner multiplication can't overflow because
188                    // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES
189                    fractional.checked_mul(fractional_factor).unwrap(),
190                )
191                .map_err(|_| StdError::msg("Value too big"))?;
192        }
193
194        if parts_iter.next().is_some() {
195            return Err(StdError::msg("Unexpected number of dots"));
196        }
197
198        Ok(Self(Decimal256::new(atomics)))
199    }
200}
201
202impl Sum for BigDecimal {
203    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
204        iter.fold(Self::zero(), Add::add)
205    }
206}
207
208impl<'a> Sum<&'a BigDecimal> for BigDecimal {
209    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
210        iter.fold(Self::zero(), |a, b| a + *b)
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use crate::bigdecimal::BigDecimal;
217    use crate::biginteger::BigInteger;
218    use cosmwasm_std::Uint256;
219
220    #[test]
221    fn test_bytes() {
222        let bigdecimal = BigDecimal::from(BigInteger(Uint256::from(1000000u64)), 0);
223
224        assert_eq!(
225            BigDecimal::from_be_bytes(bigdecimal.to_be_bytes()),
226            bigdecimal
227        );
228    }
229}