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