mars_core/math/
decimal.rs

1/// NOTE: This was copied from the cosmwasm_std package: https://github.com/CosmWasm/cosmwasm/blob/v0.16.2/packages/std/src/math/decimal.rs
2/// but modified to do some custom operations the protocol needed.
3use schemars::JsonSchema;
4use serde::{de, ser, Deserialize, Deserializer, Serialize};
5use std::fmt::{self, Write};
6use std::ops;
7use std::str::FromStr;
8
9use cosmwasm_std::Decimal as StdDecimal;
10use cosmwasm_std::{Fraction, StdError, StdResult, Uint128, Uint256};
11use std::convert::TryInto;
12
13/// A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0
14///
15/// The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)
16#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
17pub struct Decimal(#[schemars(with = "String")] Uint128);
18
19impl Decimal {
20    const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); // 1*10**18
21    const DECIMAL_FRACTIONAL_SQUARED: Uint128 =
22        Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); // (1*10**18)**2 = 1*10**36
23    const DECIMAL_PLACES: usize = 18; // This needs to be an even number.
24
25    pub const MAX: Self = Self(Uint128::MAX);
26
27    /// Create a 1.0 Decimal
28    pub const fn one() -> Self {
29        Decimal(Self::DECIMAL_FRACTIONAL)
30    }
31
32    /// Create a 0.0 Decimal
33    pub const fn zero() -> Self {
34        Decimal(Uint128::zero())
35    }
36
37    /// Convert x% into Decimal
38    pub fn percent(x: u64) -> Self {
39        Decimal(((x as u128) * 10_000_000_000_000_000).into())
40    }
41
42    /// Convert permille (x/1000) into Decimal
43    pub fn permille(x: u64) -> Self {
44        Decimal(((x as u128) * 1_000_000_000_000_000).into())
45    }
46
47    /// Returns the ratio (numerator / denominator) as a Decimal
48    pub fn from_ratio(numerator: impl Into<Uint128>, denominator: impl Into<Uint128>) -> Self {
49        let numerator: Uint128 = numerator.into();
50        let denominator: Uint128 = denominator.into();
51        if denominator.is_zero() {
52            panic!("Denominator must not be zero");
53        }
54
55        Decimal(
56            // numerator * DECIMAL_FRACTIONAL / denominator
57            numerator.multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator),
58        )
59    }
60
61    pub fn is_zero(&self) -> bool {
62        self.0.is_zero()
63    }
64
65    /// Multiply 'self' by 'other'.
66    /// Function can return errors such as:
67    /// - OverflowError from multiplication,
68    /// - ConversionOverflowError during Uint256 to Uint128 conversion.
69    pub fn checked_mul(self, other: Self) -> StdResult<Self> {
70        let a_numerator = self.numerator();
71        let b_numerator = other.numerator();
72
73        let mul_result = Uint256::from(a_numerator).checked_mul(Uint256::from(b_numerator))?;
74        let result = (mul_result / Uint256::from(Self::DECIMAL_FRACTIONAL)).try_into()?;
75        Ok(Decimal(result))
76    }
77
78    /// Divide 'self' by 'other'.
79    /// Function can return errors such as:
80    /// - OverflowError from multiplication,
81    /// - DivideByZeroError if 'other' is equal to 0,
82    /// - ConversionOverflowError during Uint256 to Uint128 conversion.
83    pub fn checked_div(self, other: Self) -> StdResult<Self> {
84        let a_numerator = self.numerator();
85        let b_numerator = other.numerator();
86
87        let mul_result =
88            Uint256::from(a_numerator).checked_mul(Uint256::from(Self::DECIMAL_FRACTIONAL))?;
89        let result = (mul_result.checked_div(Uint256::from(b_numerator)))?.try_into()?;
90        Ok(Decimal(result))
91    }
92
93    /// Divide Uint128 by Decimal.
94    /// (Uint128 / numerator / denominator) is equal to (Uint128 * denominator / numerator).
95    pub fn divide_uint128_by_decimal(a: Uint128, b: Decimal) -> StdResult<Uint128> {
96        // (Uint128 / numerator / denominator) is equal to (Uint128 * denominator / numerator).
97        let numerator_u256 = a.full_mul(b.denominator());
98        let denominator_u256 = Uint256::from(b.numerator());
99
100        let result_u256 = numerator_u256 / denominator_u256;
101
102        let result = result_u256.try_into()?;
103        Ok(result)
104    }
105
106    /// Divide Uint128 by Decimal, rounding up to the nearest integer.
107    pub fn divide_uint128_by_decimal_and_ceil(a: Uint128, b: Decimal) -> StdResult<Uint128> {
108        // (Uint128 / numerator / denominator) is equal to (Uint128 * denominator / numerator).
109        let numerator_u256 = a.full_mul(b.denominator());
110        let denominator_u256 = Uint256::from(b.numerator());
111
112        let mut result_u256 = numerator_u256 / denominator_u256;
113
114        if numerator_u256.checked_rem(denominator_u256)? > Uint256::zero() {
115            result_u256 += Uint256::from(1_u32);
116        }
117
118        let result = result_u256.try_into()?;
119        Ok(result)
120    }
121
122    /// Multiply Uint128 by Decimal, rounding up to the nearest integer.
123    pub fn multiply_uint128_by_decimal_and_ceil(a: Uint128, b: Decimal) -> StdResult<Uint128> {
124        let numerator_u256 = a.full_mul(b.numerator());
125        let denominator_u256 = Uint256::from(b.denominator());
126
127        let mut result_u256 = numerator_u256 / denominator_u256;
128
129        if numerator_u256.checked_rem(denominator_u256)? > Uint256::zero() {
130            result_u256 += Uint256::from(1_u32);
131        }
132
133        let result = result_u256.try_into()?;
134        Ok(result)
135    }
136
137    pub fn to_std_decimal(&self) -> StdDecimal {
138        StdDecimal::from_str(self.to_string().as_str()).unwrap()
139    }
140}
141
142impl Fraction<u128> for Decimal {
143    #[inline]
144    fn numerator(&self) -> u128 {
145        self.0.u128()
146    }
147
148    #[inline]
149    fn denominator(&self) -> u128 {
150        Self::DECIMAL_FRACTIONAL.u128()
151    }
152
153    /// Returns the multiplicative inverse `1/d` for decimal `d`.
154    ///
155    /// If `d` is zero, none is returned.
156    fn inv(&self) -> Option<Self> {
157        if self.is_zero() {
158            None
159        } else {
160            // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL.
161            // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then
162            // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`.
163            Some(Decimal(Self::DECIMAL_FRACTIONAL_SQUARED / self.0))
164        }
165    }
166}
167
168impl From<StdDecimal> for Decimal {
169    fn from(std_decimal: StdDecimal) -> Decimal {
170        Decimal(Uint128::new(std_decimal.numerator()))
171    }
172}
173
174impl FromStr for Decimal {
175    type Err = StdError;
176
177    /// Converts the decimal string to a Decimal
178    /// Possible inputs: "1.23", "1", "000012", "1.123000000"
179    /// Disallowed: "", ".23"
180    ///
181    /// This never performs any kind of rounding.
182    /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error.
183    fn from_str(input: &str) -> Result<Self, Self::Err> {
184        let mut parts_iter = input.split('.');
185
186        let whole_part = parts_iter.next().unwrap(); // split always returns at least one element
187        let whole = whole_part
188            .parse::<Uint128>()
189            .map_err(|_| StdError::generic_err("Error parsing whole"))?;
190        let mut atomics = whole
191            .checked_mul(Self::DECIMAL_FRACTIONAL)
192            .map_err(|_| StdError::generic_err("Value too big"))?;
193
194        if let Some(fractional_part) = parts_iter.next() {
195            let fractional = fractional_part
196                .parse::<Uint128>()
197                .map_err(|_| StdError::generic_err("Error parsing fractional"))?;
198            let exp =
199                (Self::DECIMAL_PLACES.checked_sub(fractional_part.len())).ok_or_else(|| {
200                    StdError::generic_err(format!(
201                        "Cannot parse more than {} fractional digits",
202                        Self::DECIMAL_PLACES
203                    ))
204                })?;
205            debug_assert!(exp <= Self::DECIMAL_PLACES);
206            let fractional_factor = Uint128::from(10u128.pow(exp as u32));
207            atomics = atomics
208                .checked_add(
209                    // The inner multiplication can't overflow because
210                    // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES
211                    fractional.checked_mul(fractional_factor).unwrap(),
212                )
213                .map_err(|_| StdError::generic_err("Value too big"))?;
214        }
215
216        if parts_iter.next().is_some() {
217            return Err(StdError::generic_err("Unexpected number of dots"));
218        }
219
220        Ok(Decimal(atomics))
221    }
222}
223
224impl fmt::Display for Decimal {
225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226        let whole = (self.0) / Self::DECIMAL_FRACTIONAL;
227        let fractional = (self.0).checked_rem(Self::DECIMAL_FRACTIONAL).unwrap();
228
229        if fractional.is_zero() {
230            write!(f, "{}", whole)
231        } else {
232            let fractional_string =
233                format!("{:0>padding$}", fractional, padding = Self::DECIMAL_PLACES);
234            f.write_str(&whole.to_string())?;
235            f.write_char('.')?;
236            f.write_str(fractional_string.trim_end_matches('0'))?;
237            Ok(())
238        }
239    }
240}
241
242impl ops::Add for Decimal {
243    type Output = Self;
244
245    fn add(self, other: Self) -> Self {
246        Decimal(self.0 + other.0)
247    }
248}
249
250impl ops::Sub for Decimal {
251    type Output = Self;
252
253    fn sub(self, other: Self) -> Self {
254        Decimal(self.0 - other.0)
255    }
256}
257
258/// Both d*u and u*d with d: Decimal and u: Uint128 returns an Uint128. There is no
259/// specific reason for this decision other than the initial use cases we have. If you
260/// need a Decimal result for the same calculation, use Decimal(d*u) or Decimal(u*d).
261impl ops::Mul<Decimal> for Uint128 {
262    type Output = Self;
263
264    #[allow(clippy::suspicious_arithmetic_impl)]
265    fn mul(self, rhs: Decimal) -> Self::Output {
266        // 0*a and b*0 is always 0
267        if self.is_zero() || rhs.is_zero() {
268            return Uint128::zero();
269        }
270        self.multiply_ratio(rhs.0, Decimal::DECIMAL_FRACTIONAL)
271    }
272}
273
274impl ops::Mul<Uint128> for Decimal {
275    type Output = Uint128;
276
277    fn mul(self, rhs: Uint128) -> Self::Output {
278        rhs * self
279    }
280}
281
282impl ops::Div<Uint128> for Decimal {
283    type Output = Self;
284
285    fn div(self, rhs: Uint128) -> Self::Output {
286        Decimal(self.0 / rhs)
287    }
288}
289
290impl ops::DivAssign<Uint128> for Decimal {
291    fn div_assign(&mut self, rhs: Uint128) {
292        self.0 /= rhs;
293    }
294}
295
296/// Serializes as a decimal string
297impl Serialize for Decimal {
298    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
299    where
300        S: ser::Serializer,
301    {
302        serializer.serialize_str(&self.to_string())
303    }
304}
305
306/// Deserializes as a base64 string
307impl<'de> Deserialize<'de> for Decimal {
308    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
309    where
310        D: Deserializer<'de>,
311    {
312        deserializer.deserialize_str(DecimalVisitor)
313    }
314}
315
316struct DecimalVisitor;
317
318impl<'de> de::Visitor<'de> for DecimalVisitor {
319    type Value = Decimal;
320
321    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
322        formatter.write_str("string-encoded decimal")
323    }
324
325    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
326    where
327        E: de::Error,
328    {
329        match Decimal::from_str(v) {
330            Ok(d) => Ok(d),
331            Err(e) => Err(E::custom(format!("Error parsing decimal '{}': {}", v, e))),
332        }
333    }
334}
335
336#[cfg(test)]
337mod tests {
338    use super::*;
339    use cosmwasm_std::{from_slice, to_vec, ConversionOverflowError};
340
341    #[test]
342    fn decimal_one() {
343        let value = Decimal::one();
344        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL);
345    }
346
347    #[test]
348    fn decimal_zero() {
349        let value = Decimal::zero();
350        assert!(value.0.is_zero());
351    }
352
353    #[test]
354    fn decimal_percent() {
355        let value = Decimal::percent(50);
356        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(2u8));
357    }
358
359    #[test]
360    fn decimal_permille() {
361        let value = Decimal::permille(125);
362        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(8u8));
363    }
364
365    #[test]
366    fn decimal_from_ratio_works() {
367        // 1.0
368        assert_eq!(Decimal::from_ratio(1u128, 1u128), Decimal::one());
369        assert_eq!(Decimal::from_ratio(53u128, 53u128), Decimal::one());
370        assert_eq!(Decimal::from_ratio(125u128, 125u128), Decimal::one());
371
372        // 1.5
373        assert_eq!(Decimal::from_ratio(3u128, 2u128), Decimal::percent(150));
374        assert_eq!(Decimal::from_ratio(150u128, 100u128), Decimal::percent(150));
375        assert_eq!(Decimal::from_ratio(333u128, 222u128), Decimal::percent(150));
376
377        // 0.125
378        assert_eq!(Decimal::from_ratio(1u64, 8u64), Decimal::permille(125));
379        assert_eq!(Decimal::from_ratio(125u64, 1000u64), Decimal::permille(125));
380
381        // 1/3 (result floored)
382        assert_eq!(
383            Decimal::from_ratio(1u64, 3u64),
384            Decimal(Uint128::from(333_333_333_333_333_333u128))
385        );
386
387        // 2/3 (result floored)
388        assert_eq!(
389            Decimal::from_ratio(2u64, 3u64),
390            Decimal(Uint128::from(666_666_666_666_666_666u128))
391        );
392
393        // large inputs
394        assert_eq!(Decimal::from_ratio(0u128, u128::MAX), Decimal::zero());
395        assert_eq!(Decimal::from_ratio(u128::MAX, u128::MAX), Decimal::one());
396        // 340282366920938463463 is the largest integer <= Decimal::MAX
397        assert_eq!(
398            Decimal::from_ratio(340282366920938463463u128, 1u128),
399            Decimal::from_str("340282366920938463463").unwrap()
400        );
401    }
402
403    #[test]
404    #[should_panic(expected = "Denominator must not be zero")]
405    fn decimal_from_ratio_panics_for_zero_denominator() {
406        Decimal::from_ratio(1u128, 0u128);
407    }
408
409    #[test]
410    fn decimal_implements_fraction() {
411        let fraction = Decimal::from_str("1234.567").unwrap();
412        assert_eq!(fraction.numerator(), 1_234_567_000_000_000_000_000u128);
413        assert_eq!(fraction.denominator(), 1_000_000_000_000_000_000u128);
414    }
415
416    #[test]
417    fn decimal_from_str_works() {
418        // Integers
419        assert_eq!(Decimal::from_str("0").unwrap(), Decimal::percent(0));
420        assert_eq!(Decimal::from_str("1").unwrap(), Decimal::percent(100));
421        assert_eq!(Decimal::from_str("5").unwrap(), Decimal::percent(500));
422        assert_eq!(Decimal::from_str("42").unwrap(), Decimal::percent(4200));
423        assert_eq!(Decimal::from_str("000").unwrap(), Decimal::percent(0));
424        assert_eq!(Decimal::from_str("001").unwrap(), Decimal::percent(100));
425        assert_eq!(Decimal::from_str("005").unwrap(), Decimal::percent(500));
426        assert_eq!(Decimal::from_str("0042").unwrap(), Decimal::percent(4200));
427
428        // Decimals
429        assert_eq!(Decimal::from_str("1.0").unwrap(), Decimal::percent(100));
430        assert_eq!(Decimal::from_str("1.5").unwrap(), Decimal::percent(150));
431        assert_eq!(Decimal::from_str("0.5").unwrap(), Decimal::percent(50));
432        assert_eq!(Decimal::from_str("0.123").unwrap(), Decimal::permille(123));
433
434        assert_eq!(Decimal::from_str("40.00").unwrap(), Decimal::percent(4000));
435        assert_eq!(Decimal::from_str("04.00").unwrap(), Decimal::percent(400));
436        assert_eq!(Decimal::from_str("00.40").unwrap(), Decimal::percent(40));
437        assert_eq!(Decimal::from_str("00.04").unwrap(), Decimal::percent(4));
438
439        // Can handle DECIMAL_PLACES fractional digits
440        assert_eq!(
441            Decimal::from_str("7.123456789012345678").unwrap(),
442            Decimal(Uint128::from(7123456789012345678u128))
443        );
444        assert_eq!(
445            Decimal::from_str("7.999999999999999999").unwrap(),
446            Decimal(Uint128::from(7999999999999999999u128))
447        );
448
449        // Works for documented max value
450        assert_eq!(
451            Decimal::from_str("340282366920938463463.374607431768211455").unwrap(),
452            Decimal::MAX
453        );
454    }
455
456    #[test]
457    fn decimal_from_str_errors_for_broken_whole_part() {
458        match Decimal::from_str("").unwrap_err() {
459            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"),
460            e => panic!("Unexpected error: {:?}", e),
461        }
462
463        match Decimal::from_str(" ").unwrap_err() {
464            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"),
465            e => panic!("Unexpected error: {:?}", e),
466        }
467
468        match Decimal::from_str("-1").unwrap_err() {
469            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"),
470            e => panic!("Unexpected error: {:?}", e),
471        }
472    }
473
474    #[test]
475    fn decimal_from_str_errors_for_broken_fractinal_part() {
476        match Decimal::from_str("1.").unwrap_err() {
477            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
478            e => panic!("Unexpected error: {:?}", e),
479        }
480
481        match Decimal::from_str("1. ").unwrap_err() {
482            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
483            e => panic!("Unexpected error: {:?}", e),
484        }
485
486        match Decimal::from_str("1.e").unwrap_err() {
487            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
488            e => panic!("Unexpected error: {:?}", e),
489        }
490
491        match Decimal::from_str("1.2e3").unwrap_err() {
492            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
493            e => panic!("Unexpected error: {:?}", e),
494        }
495    }
496
497    #[test]
498    fn decimal_from_str_errors_for_more_than_18_fractional_digits() {
499        match Decimal::from_str("7.1234567890123456789").unwrap_err() {
500            StdError::GenericErr { msg, .. } => {
501                assert_eq!(msg, "Cannot parse more than 18 fractional digits",)
502            }
503            e => panic!("Unexpected error: {:?}", e),
504        }
505
506        // No special rules for trailing zeros. This could be changed but adds gas cost for the happy path.
507        match Decimal::from_str("7.1230000000000000000").unwrap_err() {
508            StdError::GenericErr { msg, .. } => {
509                assert_eq!(msg, "Cannot parse more than 18 fractional digits")
510            }
511            e => panic!("Unexpected error: {:?}", e),
512        }
513    }
514
515    #[test]
516    fn decimal_from_str_errors_for_invalid_number_of_dots() {
517        match Decimal::from_str("1.2.3").unwrap_err() {
518            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"),
519            e => panic!("Unexpected error: {:?}", e),
520        }
521
522        match Decimal::from_str("1.2.3.4").unwrap_err() {
523            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"),
524            e => panic!("Unexpected error: {:?}", e),
525        }
526    }
527
528    #[test]
529    fn decimal_from_str_errors_for_more_than_max_value() {
530        // Integer
531        match Decimal::from_str("340282366920938463464").unwrap_err() {
532            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"),
533            e => panic!("Unexpected error: {:?}", e),
534        }
535
536        // Decimal
537        match Decimal::from_str("340282366920938463464.0").unwrap_err() {
538            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"),
539            e => panic!("Unexpected error: {:?}", e),
540        }
541        match Decimal::from_str("340282366920938463463.374607431768211456").unwrap_err() {
542            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"),
543            e => panic!("Unexpected error: {:?}", e),
544        }
545    }
546
547    #[test]
548    fn decimal_is_zero_works() {
549        assert!(Decimal::zero().is_zero());
550        assert!(Decimal::percent(0).is_zero());
551        assert!(Decimal::permille(0).is_zero());
552
553        assert!(!Decimal::one().is_zero());
554        assert!(!Decimal::percent(123).is_zero());
555        assert!(!Decimal::permille(1234).is_zero());
556    }
557
558    #[test]
559    fn decimal_inv_works() {
560        // d = 0
561        assert_eq!(Decimal::zero().inv(), None);
562
563        // d == 1
564        assert_eq!(Decimal::one().inv(), Some(Decimal::one()));
565
566        // d > 1 exact
567        assert_eq!(
568            Decimal::from_str("2").unwrap().inv(),
569            Some(Decimal::from_str("0.5").unwrap())
570        );
571        assert_eq!(
572            Decimal::from_str("20").unwrap().inv(),
573            Some(Decimal::from_str("0.05").unwrap())
574        );
575        assert_eq!(
576            Decimal::from_str("200").unwrap().inv(),
577            Some(Decimal::from_str("0.005").unwrap())
578        );
579        assert_eq!(
580            Decimal::from_str("2000").unwrap().inv(),
581            Some(Decimal::from_str("0.0005").unwrap())
582        );
583
584        // d > 1 rounded
585        assert_eq!(
586            Decimal::from_str("3").unwrap().inv(),
587            Some(Decimal::from_str("0.333333333333333333").unwrap())
588        );
589        assert_eq!(
590            Decimal::from_str("6").unwrap().inv(),
591            Some(Decimal::from_str("0.166666666666666666").unwrap())
592        );
593
594        // d < 1 exact
595        assert_eq!(
596            Decimal::from_str("0.5").unwrap().inv(),
597            Some(Decimal::from_str("2").unwrap())
598        );
599        assert_eq!(
600            Decimal::from_str("0.05").unwrap().inv(),
601            Some(Decimal::from_str("20").unwrap())
602        );
603        assert_eq!(
604            Decimal::from_str("0.005").unwrap().inv(),
605            Some(Decimal::from_str("200").unwrap())
606        );
607        assert_eq!(
608            Decimal::from_str("0.0005").unwrap().inv(),
609            Some(Decimal::from_str("2000").unwrap())
610        );
611    }
612
613    #[test]
614    fn decimal_add() {
615        let value = Decimal::one() + Decimal::percent(50); // 1.5
616        assert_eq!(
617            value.0,
618            Decimal::DECIMAL_FRACTIONAL * Uint128::from(3u8) / Uint128::from(2u8)
619        );
620    }
621
622    #[test]
623    #[should_panic(expected = "attempt to add with overflow")]
624    fn decimal_add_overflow_panics() {
625        let _value = Decimal::MAX + Decimal::percent(50);
626    }
627
628    #[test]
629    fn decimal_sub() {
630        let value = Decimal::one() - Decimal::percent(50); // 0.5
631        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(2u8));
632    }
633
634    #[test]
635    #[should_panic(expected = "attempt to subtract with overflow")]
636    fn decimal_sub_overflow_panics() {
637        let _value = Decimal::zero() - Decimal::percent(50);
638    }
639
640    #[test]
641    // in this test the Decimal is on the right
642    fn uint128_decimal_multiply() {
643        // a*b
644        let left = Uint128::new(300);
645        let right = Decimal::one() + Decimal::percent(50); // 1.5
646        assert_eq!(left * right, Uint128::new(450));
647
648        // a*0
649        let left = Uint128::new(300);
650        let right = Decimal::zero();
651        assert_eq!(left * right, Uint128::new(0));
652
653        // 0*a
654        let left = Uint128::new(0);
655        let right = Decimal::one() + Decimal::percent(50); // 1.5
656        assert_eq!(left * right, Uint128::new(0));
657    }
658
659    #[test]
660    // in this test the Decimal is on the left
661    fn decimal_uint128_multiply() {
662        // a*b
663        let left = Decimal::one() + Decimal::percent(50); // 1.5
664        let right = Uint128::new(300);
665        assert_eq!(left * right, Uint128::new(450));
666
667        // 0*a
668        let left = Decimal::zero();
669        let right = Uint128::new(300);
670        assert_eq!(left * right, Uint128::new(0));
671
672        // a*0
673        let left = Decimal::one() + Decimal::percent(50); // 1.5
674        let right = Uint128::new(0);
675        assert_eq!(left * right, Uint128::new(0));
676    }
677
678    #[test]
679    fn decimal_uint128_division() {
680        // a/b
681        let left = Decimal::percent(150); // 1.5
682        let right = Uint128::new(3);
683        assert_eq!(left / right, Decimal::percent(50));
684
685        // 0/a
686        let left = Decimal::zero();
687        let right = Uint128::new(300);
688        assert_eq!(left / right, Decimal::zero());
689    }
690
691    #[test]
692    #[should_panic(expected = "attempt to divide by zero")]
693    fn decimal_uint128_divide_by_zero() {
694        let left = Decimal::percent(150); // 1.5
695        let right = Uint128::new(0);
696        let _result = left / right;
697    }
698
699    #[test]
700    fn decimal_uint128_div_assign() {
701        // a/b
702        let mut dec = Decimal::percent(150); // 1.5
703        dec /= Uint128::new(3);
704        assert_eq!(dec, Decimal::percent(50));
705
706        // 0/a
707        let mut dec = Decimal::zero();
708        dec /= Uint128::new(300);
709        assert_eq!(dec, Decimal::zero());
710    }
711
712    #[test]
713    #[should_panic(expected = "attempt to divide by zero")]
714    fn decimal_uint128_div_assign_by_zero() {
715        // a/0
716        let mut dec = Decimal::percent(50);
717        dec /= Uint128::new(0);
718    }
719
720    #[test]
721    fn checked_decimal_multiplication() {
722        let a = Decimal::from_ratio(33u128, 10u128);
723        let b = Decimal::from_ratio(45u128, 10u128);
724        let c = Decimal::checked_mul(a, b).unwrap();
725        assert_eq!(c, Decimal::from_str("14.85").unwrap());
726
727        let a = Decimal::from_ratio(340282366920u128, 1u128);
728        let b = Decimal::from_ratio(12345678u128, 100000000u128);
729        let c = Decimal::checked_mul(a, b).unwrap();
730        assert_eq!(c, Decimal::from_str("42010165310.7217176").unwrap());
731
732        let a = Decimal::MAX;
733        let b = Decimal::one();
734        let c = Decimal::checked_mul(a, b).unwrap();
735        assert_eq!(c, Decimal::MAX);
736
737        let a = Decimal::MAX;
738        let b = Decimal::MAX;
739        let res_error = Decimal::checked_mul(a, b).unwrap_err();
740        assert_eq!(
741            res_error,
742            ConversionOverflowError::new(
743                "Uint256",
744                "Uint128",
745                "115792089237316195423570985008687907852589419931798687112530"
746            )
747            .into()
748        );
749    }
750
751    #[test]
752    fn checked_decimal_division() {
753        let a = Decimal::from_ratio(99988u128, 100u128);
754        let b = Decimal::from_ratio(24997u128, 100u128);
755        let c = Decimal::checked_div(a, b).unwrap();
756        assert_eq!(c, Decimal::from_str("4.0").unwrap());
757
758        let a = Decimal::from_ratio(123456789u128, 1000000u128);
759        let b = Decimal::from_ratio(33u128, 1u128);
760        let c = Decimal::checked_div(a, b).unwrap();
761        assert_eq!(c, Decimal::from_str("3.741114818181818181").unwrap());
762
763        let a = Decimal::MAX;
764        let b = Decimal::MAX;
765        let c = Decimal::checked_div(a, b).unwrap();
766        assert_eq!(c, Decimal::one());
767
768        // Note: DivideByZeroError is not public so we just check if dividing by zero returns error
769        let a = Decimal::one();
770        let b = Decimal::zero();
771        Decimal::checked_div(a, b).unwrap_err();
772
773        let a = Decimal::MAX;
774        let b = Decimal::from_ratio(1u128, Decimal::DECIMAL_FRACTIONAL);
775        let res_error = Decimal::checked_div(a, b).unwrap_err();
776        assert_eq!(
777            res_error,
778            ConversionOverflowError::new(
779                "Uint256",
780                "Uint128",
781                "340282366920938463463374607431768211455000000000000000000"
782            )
783            .into()
784        );
785    }
786
787    #[test]
788    fn test_divide_uint128_by_decimal() {
789        let a = Uint128::new(120u128);
790        let b = Decimal::from_ratio(120u128, 15u128);
791        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
792        assert_eq!(c, Uint128::new(15u128));
793
794        let a = Uint128::new(Decimal::DECIMAL_FRACTIONAL.u128());
795        let b = Decimal::from_ratio(Decimal::DECIMAL_FRACTIONAL.u128(), 1u128);
796        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
797        assert_eq!(c, Uint128::new(1u128));
798
799        let a = Uint128::new(Decimal::DECIMAL_FRACTIONAL.u128());
800        let b = Decimal::from_ratio(1u128, Decimal::DECIMAL_FRACTIONAL.u128());
801        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
802        assert_eq!(c, Uint128::new(Decimal::DECIMAL_FRACTIONAL_SQUARED.u128()));
803
804        let a = Uint128::MAX;
805        let b = Decimal::one();
806        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
807        assert_eq!(c, Uint128::MAX);
808
809        let a = Uint128::new(1_000_000_000_000_000_000);
810        let b = Decimal::from_ratio(1u128, Decimal::DECIMAL_FRACTIONAL);
811        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
812        assert_eq!(
813            c,
814            Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000)
815        );
816
817        // Division is truncated
818        let a = Uint128::new(100);
819        let b = Decimal::from_ratio(3u128, 1u128);
820        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
821        assert_eq!(c, Uint128::new(33));
822
823        let a = Uint128::new(75);
824        let b = Decimal::from_ratio(100u128, 1u128);
825        let c = Decimal::divide_uint128_by_decimal(a, b).unwrap();
826        assert_eq!(c, Uint128::new(0));
827
828        // Overflow
829        let a = Uint128::MAX;
830        let b = Decimal::from_ratio(1_u128, 10_u128);
831        let res_error = Decimal::divide_uint128_by_decimal(a, b).unwrap_err();
832        assert_eq!(
833            res_error,
834            ConversionOverflowError::new(
835                "Uint256",
836                "Uint128",
837                "3402823669209384634633746074317682114550"
838            )
839            .into()
840        );
841    }
842
843    #[test]
844    fn test_divide_uint128_by_decimal_and_ceil() {
845        let a = Uint128::new(120u128);
846        let b = Decimal::from_ratio(120u128, 15u128);
847        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
848        assert_eq!(c, Uint128::new(15u128));
849
850        let a = Uint128::new(Decimal::DECIMAL_FRACTIONAL.u128());
851        let b = Decimal::from_ratio(Decimal::DECIMAL_FRACTIONAL.u128(), 1u128);
852        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
853        assert_eq!(c, Uint128::new(1u128));
854
855        let a = Uint128::new(Decimal::DECIMAL_FRACTIONAL.u128());
856        let b = Decimal::from_ratio(1u128, Decimal::DECIMAL_FRACTIONAL.u128());
857        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
858        assert_eq!(c, Uint128::new(Decimal::DECIMAL_FRACTIONAL_SQUARED.u128()));
859
860        let a = Uint128::MAX;
861        let b = Decimal::one();
862        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
863        assert_eq!(c, Uint128::MAX);
864
865        let a = Uint128::new(1_000_000_000_000_000_000);
866        let b = Decimal::from_ratio(1u128, Decimal::DECIMAL_FRACTIONAL);
867        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
868        assert_eq!(
869            c,
870            Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000)
871        );
872
873        // Division is rounded up
874        let a = Uint128::new(100);
875        let b = Decimal::from_ratio(3u128, 1u128);
876        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
877        assert_eq!(c, Uint128::new(34));
878
879        let a = Uint128::new(75);
880        let b = Decimal::from_ratio(100u128, 1u128);
881        let c = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap();
882        assert_eq!(c, Uint128::new(1));
883
884        // Overflow
885        let a = Uint128::MAX;
886        let b = Decimal::from_ratio(1_u128, 10_u128);
887        let res_error = Decimal::divide_uint128_by_decimal_and_ceil(a, b).unwrap_err();
888        assert_eq!(
889            res_error,
890            ConversionOverflowError::new(
891                "Uint256",
892                "Uint128",
893                "3402823669209384634633746074317682114550"
894            )
895            .into()
896        );
897    }
898
899    #[test]
900    fn decimal_to_std_decimal() {
901        let custom_decimal_1 = Decimal::from_ratio(240u128, 500u128);
902        let std_decimal_1_expected = StdDecimal::from_ratio(240u128, 500u128);
903        assert_eq!(custom_decimal_1.to_std_decimal(), std_decimal_1_expected);
904
905        let custom_decimal_2 = Decimal::from_ratio(333u128, 1000u128);
906        let std_decimal_2_expected = StdDecimal::from_ratio(333u128, 1000u128);
907        assert_eq!(custom_decimal_2.to_std_decimal(), std_decimal_2_expected);
908    }
909
910    #[test]
911    fn decimal_to_string() {
912        // Integers
913        assert_eq!(Decimal::zero().to_string(), "0");
914        assert_eq!(Decimal::one().to_string(), "1");
915        assert_eq!(Decimal::percent(500).to_string(), "5");
916
917        // Decimals
918        assert_eq!(Decimal::percent(125).to_string(), "1.25");
919        assert_eq!(Decimal::percent(42638).to_string(), "426.38");
920        assert_eq!(Decimal::percent(3).to_string(), "0.03");
921        assert_eq!(Decimal::permille(987).to_string(), "0.987");
922
923        assert_eq!(
924            Decimal(Uint128::from(1u128)).to_string(),
925            "0.000000000000000001"
926        );
927        assert_eq!(
928            Decimal(Uint128::from(10u128)).to_string(),
929            "0.00000000000000001"
930        );
931        assert_eq!(
932            Decimal(Uint128::from(100u128)).to_string(),
933            "0.0000000000000001"
934        );
935        assert_eq!(
936            Decimal(Uint128::from(1000u128)).to_string(),
937            "0.000000000000001"
938        );
939        assert_eq!(
940            Decimal(Uint128::from(10000u128)).to_string(),
941            "0.00000000000001"
942        );
943        assert_eq!(
944            Decimal(Uint128::from(100000u128)).to_string(),
945            "0.0000000000001"
946        );
947        assert_eq!(
948            Decimal(Uint128::from(1000000u128)).to_string(),
949            "0.000000000001"
950        );
951        assert_eq!(
952            Decimal(Uint128::from(10000000u128)).to_string(),
953            "0.00000000001"
954        );
955        assert_eq!(
956            Decimal(Uint128::from(100000000u128)).to_string(),
957            "0.0000000001"
958        );
959        assert_eq!(
960            Decimal(Uint128::from(1000000000u128)).to_string(),
961            "0.000000001"
962        );
963        assert_eq!(
964            Decimal(Uint128::from(10000000000u128)).to_string(),
965            "0.00000001"
966        );
967        assert_eq!(
968            Decimal(Uint128::from(100000000000u128)).to_string(),
969            "0.0000001"
970        );
971        assert_eq!(
972            Decimal(Uint128::from(10000000000000u128)).to_string(),
973            "0.00001"
974        );
975        assert_eq!(
976            Decimal(Uint128::from(100000000000000u128)).to_string(),
977            "0.0001"
978        );
979        assert_eq!(
980            Decimal(Uint128::from(1000000000000000u128)).to_string(),
981            "0.001"
982        );
983        assert_eq!(
984            Decimal(Uint128::from(10000000000000000u128)).to_string(),
985            "0.01"
986        );
987        assert_eq!(
988            Decimal(Uint128::from(100000000000000000u128)).to_string(),
989            "0.1"
990        );
991    }
992
993    #[test]
994    fn decimal_serialize() {
995        assert_eq!(to_vec(&Decimal::zero()).unwrap(), br#""0""#);
996        assert_eq!(to_vec(&Decimal::one()).unwrap(), br#""1""#);
997        assert_eq!(to_vec(&Decimal::percent(8)).unwrap(), br#""0.08""#);
998        assert_eq!(to_vec(&Decimal::percent(87)).unwrap(), br#""0.87""#);
999        assert_eq!(to_vec(&Decimal::percent(876)).unwrap(), br#""8.76""#);
1000        assert_eq!(to_vec(&Decimal::percent(8765)).unwrap(), br#""87.65""#);
1001    }
1002
1003    #[test]
1004    fn decimal_deserialize() {
1005        assert_eq!(from_slice::<Decimal>(br#""0""#).unwrap(), Decimal::zero());
1006        assert_eq!(from_slice::<Decimal>(br#""1""#).unwrap(), Decimal::one());
1007        assert_eq!(from_slice::<Decimal>(br#""000""#).unwrap(), Decimal::zero());
1008        assert_eq!(from_slice::<Decimal>(br#""001""#).unwrap(), Decimal::one());
1009
1010        assert_eq!(
1011            from_slice::<Decimal>(br#""0.08""#).unwrap(),
1012            Decimal::percent(8)
1013        );
1014        assert_eq!(
1015            from_slice::<Decimal>(br#""0.87""#).unwrap(),
1016            Decimal::percent(87)
1017        );
1018        assert_eq!(
1019            from_slice::<Decimal>(br#""8.76""#).unwrap(),
1020            Decimal::percent(876)
1021        );
1022        assert_eq!(
1023            from_slice::<Decimal>(br#""87.65""#).unwrap(),
1024            Decimal::percent(8765)
1025        );
1026    }
1027
1028    #[test]
1029    fn std_decimal_compatibility() {
1030        // StdDecimal can be serialized to Decimal
1031        assert_eq!(
1032            from_slice::<Decimal>(&to_vec(&StdDecimal::zero()).unwrap()).unwrap(),
1033            Decimal::zero()
1034        );
1035        assert_eq!(
1036            from_slice::<Decimal>(&to_vec(&StdDecimal::percent(8)).unwrap()).unwrap(),
1037            Decimal::percent(8)
1038        );
1039        assert_eq!(
1040            from_slice::<Decimal>(&to_vec(&StdDecimal::percent(87)).unwrap()).unwrap(),
1041            Decimal::percent(87)
1042        );
1043        assert_eq!(
1044            from_slice::<Decimal>(&to_vec(&StdDecimal::percent(876)).unwrap()).unwrap(),
1045            Decimal::percent(876)
1046        );
1047        assert_eq!(
1048            from_slice::<Decimal>(&to_vec(&StdDecimal::percent(8765)).unwrap()).unwrap(),
1049            Decimal::percent(8765)
1050        );
1051        assert_eq!(
1052            from_slice::<Decimal>(
1053                &to_vec(&StdDecimal::from_ratio(3423423424000000_u128, 223_u128)).unwrap()
1054            )
1055            .unwrap(),
1056            Decimal::from_ratio(3423423424000000_u128, 223_u128)
1057        );
1058        assert_eq!(
1059            from_slice::<Decimal>(
1060                &to_vec(&StdDecimal::from_ratio(
1061                    123_u128,
1062                    3424234234823842093840923848098409238_u128
1063                ))
1064                .unwrap()
1065            )
1066            .unwrap(),
1067            Decimal::from_ratio(123_u128, 3424234234823842093840923848098409238_u128)
1068        );
1069
1070        // Decimal can be serialized to StdDecimal
1071        assert_eq!(
1072            from_slice::<StdDecimal>(&to_vec(&Decimal::zero()).unwrap()).unwrap(),
1073            StdDecimal::zero()
1074        );
1075        assert_eq!(
1076            from_slice::<StdDecimal>(&to_vec(&Decimal::percent(8)).unwrap()).unwrap(),
1077            StdDecimal::percent(8)
1078        );
1079        assert_eq!(
1080            from_slice::<StdDecimal>(&to_vec(&Decimal::percent(87)).unwrap()).unwrap(),
1081            StdDecimal::percent(87)
1082        );
1083        assert_eq!(
1084            from_slice::<StdDecimal>(&to_vec(&Decimal::percent(876)).unwrap()).unwrap(),
1085            StdDecimal::percent(876)
1086        );
1087        assert_eq!(
1088            from_slice::<StdDecimal>(&to_vec(&Decimal::percent(8765)).unwrap()).unwrap(),
1089            StdDecimal::percent(8765)
1090        );
1091        assert_eq!(
1092            from_slice::<StdDecimal>(
1093                &to_vec(&Decimal::from_ratio(3423423424000000_u128, 223_u128)).unwrap()
1094            )
1095            .unwrap(),
1096            StdDecimal::from_ratio(3423423424000000_u128, 223_u128)
1097        );
1098        assert_eq!(
1099            from_slice::<StdDecimal>(
1100                &to_vec(&Decimal::from_ratio(
1101                    123_u128,
1102                    3424234234823842093840923848098409238_u128
1103                ))
1104                .unwrap()
1105            )
1106            .unwrap(),
1107            StdDecimal::from_ratio(123_u128, 3424234234823842093840923848098409238_u128)
1108        );
1109    }
1110}