cosmwasm_common_library/
bigdecimal.rs1use 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 = 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(); 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 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}