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
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 = 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(); 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 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}