Skip to main content

cosmwasm_std/math/
decimal.rs

1use alloc::string::ToString;
2use core::cmp::Ordering;
3use core::fmt::{self, Write};
4use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
5use core::str::FromStr;
6use serde::{de, ser, Deserialize, Deserializer, Serialize};
7
8use crate::errors::{
9    CheckedFromRatioError, CheckedMultiplyRatioError, DivideByZeroError, ErrorKind, OverflowError,
10    OverflowOperation, RoundUpOverflowError, StdError,
11};
12use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
13use crate::{Decimal256, SignedDecimal, SignedDecimal256, __internal::forward_ref_partial_eq};
14
15use super::Fraction;
16use super::Isqrt;
17use super::{Uint128, Uint256};
18
19/// A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0
20///
21/// The greatest possible value that can be represented is 340282366920938463463.374607431768211455 = (2^128 - 1) / 10^18
22#[derive(
23    Copy,
24    Clone,
25    Default,
26    PartialEq,
27    Eq,
28    PartialOrd,
29    Ord,
30    schemars::JsonSchema,
31    cw_schema::Schemaifier,
32)]
33#[schemaifier(type = cw_schema::NodeType::Decimal { precision: 128, signed: false })]
34pub struct Decimal(#[schemars(with = "String")] Uint128);
35
36forward_ref_partial_eq!(Decimal, Decimal);
37
38#[derive(Debug, PartialEq, Eq, thiserror::Error)]
39#[error("Decimal range exceeded")]
40pub struct DecimalRangeExceeded;
41
42impl Decimal {
43    const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); // 1*10**18
44    const DECIMAL_FRACTIONAL_SQUARED: Uint128 =
45        Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); // (1*10**18)**2 = 1*10**36
46
47    /// The number of decimal places. Since decimal types are fixed-point rather than
48    /// floating-point, this is a constant.
49    pub const DECIMAL_PLACES: u32 = 18; // This needs to be an even number.
50    /// The largest value that can be represented by this decimal type.
51    pub const MAX: Self = Self(Uint128::MAX);
52    /// The smallest value that can be represented by this decimal type.
53    pub const MIN: Self = Self(Uint128::MIN);
54
55    /// Creates a Decimal(value)
56    /// This is equivalent to `Decimal::from_atomics(value, 18)` but usable in a const context.
57    ///
58    /// ## Examples
59    ///
60    /// ```
61    /// # use cosmwasm_std::{Uint128, Decimal};
62    /// let atoms = Uint128::new(141_183_460_469_231_731_687_303_715_884_105_727_125);
63    /// let value = Decimal::new(atoms);
64    /// assert_eq!(value.to_string(), "141183460469231731687.303715884105727125");
65    /// ```
66    #[inline]
67    #[must_use]
68    pub const fn new(value: Uint128) -> Self {
69        Self(value)
70    }
71
72    /// Creates a Decimal(Uint128(value))
73    /// This is equivalent to `Decimal::from_atomics(value, 18)` but usable in a const context.
74    #[deprecated(
75        since = "3.0.0",
76        note = "Use Decimal::new(Uint128::new(value)) instead"
77    )]
78    pub const fn raw(value: u128) -> Self {
79        Self(Uint128::new(value))
80    }
81
82    /// Create a 1.0 Decimal
83    #[inline]
84    pub const fn one() -> Self {
85        Self(Self::DECIMAL_FRACTIONAL)
86    }
87
88    /// Create a 0.0 Decimal
89    #[inline]
90    pub const fn zero() -> Self {
91        Self(Uint128::zero())
92    }
93
94    /// Convert x% into Decimal
95    ///
96    /// ## Examples
97    ///
98    /// ```
99    /// # use std::str::FromStr;
100    /// # use cosmwasm_std::Decimal;
101    /// const HALF: Decimal = Decimal::percent(50);
102    ///
103    /// assert_eq!(HALF, Decimal::from_str("0.5").unwrap());
104    /// ```
105    pub const fn percent(x: u64) -> Self {
106        // multiplication does not overflow since `u64::MAX` * 10**16 is well in u128 range
107        let atomics = (x as u128) * 10_000_000_000_000_000;
108        Self(Uint128::new(atomics))
109    }
110
111    /// Convert per mille (x/1000) into Decimal
112    ///
113    /// ## Examples
114    ///
115    /// ```
116    /// # use std::str::FromStr;
117    /// # use cosmwasm_std::Decimal;
118    /// const HALF: Decimal = Decimal::permille(500);
119    ///
120    /// assert_eq!(HALF, Decimal::from_str("0.5").unwrap());
121    /// ```
122    pub const fn permille(x: u64) -> Self {
123        // multiplication does not overflow since `u64::MAX` * 10**15 is well in u128 range
124        let atomics = (x as u128) * 1_000_000_000_000_000;
125        Self(Uint128::new(atomics))
126    }
127
128    /// Convert basis points (x/10000) into Decimal
129    ///
130    /// ## Examples
131    ///
132    /// ```
133    /// # use std::str::FromStr;
134    /// # use cosmwasm_std::Decimal;
135    /// const TWO_BPS: Decimal = Decimal::bps(2);
136    /// const HALF: Decimal = Decimal::bps(5000);
137    ///
138    /// assert_eq!(TWO_BPS, Decimal::from_str("0.0002").unwrap());
139    /// assert_eq!(HALF, Decimal::from_str("0.5").unwrap());
140    /// ```
141    pub const fn bps(x: u64) -> Self {
142        // multiplication does not overflow since `u64::MAX` * 10**14 is well in u128 range
143        let atomics = (x as u128) * 100_000_000_000_000;
144        Self(Uint128::new(atomics))
145    }
146
147    /// Creates a decimal from a number of atomic units and the number
148    /// of decimal places. The inputs will be converted internally to form
149    /// a decimal with 18 decimal places. So the input 123 and 2 will create
150    /// the decimal 1.23.
151    ///
152    /// Using 18 decimal places is slightly more efficient than other values
153    /// as no internal conversion is necessary.
154    ///
155    /// ## Examples
156    ///
157    /// ```
158    /// # use cosmwasm_std::{Decimal, Uint128};
159    /// let a = Decimal::from_atomics(Uint128::new(1234), 3).unwrap();
160    /// assert_eq!(a.to_string(), "1.234");
161    ///
162    /// let a = Decimal::from_atomics(1234u128, 0).unwrap();
163    /// assert_eq!(a.to_string(), "1234");
164    ///
165    /// let a = Decimal::from_atomics(1u64, 18).unwrap();
166    /// assert_eq!(a.to_string(), "0.000000000000000001");
167    /// ```
168    pub fn from_atomics(
169        atomics: impl Into<Uint128>,
170        decimal_places: u32,
171    ) -> Result<Self, DecimalRangeExceeded> {
172        let atomics = atomics.into();
173        const TEN: Uint128 = Uint128::new(10);
174        Ok(match decimal_places.cmp(&Self::DECIMAL_PLACES) {
175            Ordering::Less => {
176                let digits = (Self::DECIMAL_PLACES) - decimal_places; // No overflow because decimal_places < DECIMAL_PLACES
177                let factor = TEN.checked_pow(digits).unwrap(); // Safe because digits <= 17
178                Self(
179                    atomics
180                        .checked_mul(factor)
181                        .map_err(|_| DecimalRangeExceeded)?,
182                )
183            }
184            Ordering::Equal => Self(atomics),
185            Ordering::Greater => {
186                let digits = decimal_places - (Self::DECIMAL_PLACES); // No overflow because decimal_places > DECIMAL_PLACES
187                if atomics.is_zero() || digits > atomics.ilog10() {
188                    // In this case `10^digits > atomics`, so the division truncates to zero.
189                    Self(Uint128::zero())
190                } else {
191                    // `digits <= ilog10(atomics)` guarantees `10^digits` fits in Uint128.
192                    let factor = TEN.checked_pow(digits).unwrap();
193                    Self(atomics.checked_div(factor).unwrap()) // Safe because factor cannot be zero
194                }
195            }
196        })
197    }
198
199    /// Returns the ratio (numerator / denominator) as a Decimal
200    pub fn from_ratio(numerator: impl Into<Uint128>, denominator: impl Into<Uint128>) -> Self {
201        match Decimal::checked_from_ratio(numerator, denominator) {
202            Ok(value) => value,
203            Err(CheckedFromRatioError::DivideByZero) => {
204                panic!("Denominator must not be zero")
205            }
206            Err(CheckedFromRatioError::Overflow) => panic!("Multiplication overflow"),
207        }
208    }
209
210    /// Returns the ratio (numerator / denominator) as a Decimal
211    pub fn checked_from_ratio(
212        numerator: impl Into<Uint128>,
213        denominator: impl Into<Uint128>,
214    ) -> Result<Self, CheckedFromRatioError> {
215        let numerator: Uint128 = numerator.into();
216        let denominator: Uint128 = denominator.into();
217        match numerator.checked_multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator) {
218            Ok(ratio) => {
219                // numerator * DECIMAL_FRACTIONAL / denominator
220                Ok(Decimal(ratio))
221            }
222            Err(CheckedMultiplyRatioError::Overflow) => Err(CheckedFromRatioError::Overflow),
223            Err(CheckedMultiplyRatioError::DivideByZero) => {
224                Err(CheckedFromRatioError::DivideByZero)
225            }
226        }
227    }
228
229    #[must_use]
230    pub const fn is_zero(&self) -> bool {
231        self.0.is_zero()
232    }
233
234    /// A decimal is an integer of atomic units plus a number that specifies the
235    /// position of the decimal dot. So any decimal can be expressed as two numbers.
236    ///
237    /// ## Examples
238    ///
239    /// ```
240    /// # use cosmwasm_std::{Decimal, Uint128};
241    /// # use core::str::FromStr;
242    /// // Value with whole and fractional part
243    /// let a = Decimal::from_str("1.234").unwrap();
244    /// assert_eq!(a.decimal_places(), 18);
245    /// assert_eq!(a.atomics(), Uint128::new(1234000000000000000));
246    ///
247    /// // Smallest possible value
248    /// let b = Decimal::from_str("0.000000000000000001").unwrap();
249    /// assert_eq!(b.decimal_places(), 18);
250    /// assert_eq!(b.atomics(), Uint128::new(1));
251    /// ```
252    #[must_use]
253    #[inline]
254    pub const fn atomics(&self) -> Uint128 {
255        self.0
256    }
257
258    /// The number of decimal places. This is a constant value for now
259    /// but this could potentially change as the type evolves.
260    ///
261    /// See also [`Decimal::atomics()`].
262    #[must_use]
263    #[inline]
264    pub const fn decimal_places(&self) -> u32 {
265        Self::DECIMAL_PLACES
266    }
267
268    /// Rounds value down after decimal places.
269    #[must_use = "this returns the result of the operation, without modifying the original"]
270    pub fn floor(&self) -> Self {
271        Self((self.0 / Self::DECIMAL_FRACTIONAL) * Self::DECIMAL_FRACTIONAL)
272    }
273
274    /// Rounds value up after decimal places. Panics on overflow.
275    #[must_use = "this returns the result of the operation, without modifying the original"]
276    pub fn ceil(&self) -> Self {
277        match self.checked_ceil() {
278            Ok(value) => value,
279            Err(_) => panic!("attempt to ceil with overflow"),
280        }
281    }
282
283    /// Rounds value up after decimal places. Returns OverflowError on overflow.
284    pub fn checked_ceil(&self) -> Result<Self, RoundUpOverflowError> {
285        let floor = self.floor();
286        if floor == self {
287            Ok(floor)
288        } else {
289            floor
290                .checked_add(Decimal::one())
291                .map_err(|_| RoundUpOverflowError)
292        }
293    }
294
295    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
296        self.0
297            .checked_add(other.0)
298            .map(Self)
299            .map_err(|_| OverflowError::new(OverflowOperation::Add))
300    }
301
302    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
303        self.0
304            .checked_sub(other.0)
305            .map(Self)
306            .map_err(|_| OverflowError::new(OverflowOperation::Sub))
307    }
308
309    /// Multiplies one `Decimal` by another, returning an `OverflowError` if an overflow occurred.
310    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
311        let result_as_uint256 = self.numerator().full_mul(other.numerator())
312            / Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); // from_uint128 is a const method and should be "free"
313        result_as_uint256
314            .try_into()
315            .map(Self)
316            .map_err(|_| OverflowError::new(OverflowOperation::Mul))
317    }
318
319    /// Raises a value to the power of `exp`, panics if an overflow occurred.
320    #[must_use = "this returns the result of the operation, without modifying the original"]
321    pub fn pow(self, exp: u32) -> Self {
322        match self.checked_pow(exp) {
323            Ok(value) => value,
324            Err(_) => panic!("Multiplication overflow"),
325        }
326    }
327
328    /// Raises a value to the power of `exp`, returning an `OverflowError` if an overflow occurred.
329    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
330        // This uses the exponentiation by squaring algorithm:
331        // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method
332
333        fn inner(mut x: Decimal, mut n: u32) -> Result<Decimal, OverflowError> {
334            if n == 0 {
335                return Ok(Decimal::one());
336            }
337
338            let mut y = Decimal::one();
339
340            while n > 1 {
341                if n % 2 == 0 {
342                    x = x.checked_mul(x)?;
343                    n /= 2;
344                } else {
345                    y = x.checked_mul(y)?;
346                    x = x.checked_mul(x)?;
347                    n = (n - 1) / 2;
348                }
349            }
350
351            Ok(x * y)
352        }
353
354        inner(self, exp).map_err(|_| OverflowError::new(OverflowOperation::Pow))
355    }
356
357    pub fn checked_div(self, other: Self) -> Result<Self, CheckedFromRatioError> {
358        Decimal::checked_from_ratio(self.numerator(), other.numerator())
359    }
360
361    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
362        self.0
363            .checked_rem(other.0)
364            .map(Self)
365            .map_err(|_| DivideByZeroError)
366    }
367
368    /// Returns the approximate square root as a Decimal.
369    ///
370    /// This should not overflow or panic.
371    #[must_use = "this returns the result of the operation, without modifying the original"]
372    pub fn sqrt(&self) -> Self {
373        // The max precision is `9 - log10(self.0) / 2`.
374        // We can optimize the previous loop by using `ilog10` to directly calculate the precision.
375        if self.0.is_zero() {
376            // value is 0, so we can use any precision, let's use the max one
377            return self.sqrt_with_precision(Self::DECIMAL_PLACES / 2).unwrap();
378        }
379
380        // 38 is the max number of digits for u128
381        // 9 is the max precision (DECIMAL_PLACES / 2)
382        let precision_guess = (38 - self.0.ilog10()) / 2;
383        let precision = core::cmp::min(precision_guess, Self::DECIMAL_PLACES / 2);
384
385        // The estimate using ilog10 might determine a precision that causes overflow for
386        // high mantissas (e.g. 4e36). In that case, we need to lower the precision by 1.
387        // We know that precision-1 is always safe because it reduces the exponent by 2.
388        self.sqrt_with_precision(precision)
389            .or_else(|| self.sqrt_with_precision(precision - 1))
390            .unwrap()
391    }
392
393    /// Lower precision means more aggressive rounding, but less risk of overflow.
394    /// Precision *must* be a number between 0 and 9 (inclusive).
395    ///
396    /// Returns `None` if the internal multiplication overflows.
397    #[must_use = "this returns the result of the operation, without modifying the original"]
398    fn sqrt_with_precision(&self, precision: u32) -> Option<Self> {
399        let inner_mul = 100u128.pow(precision);
400        self.0.checked_mul(inner_mul.into()).ok().map(|inner| {
401            let outer_mul = Uint128::from(10u128).pow(Self::DECIMAL_PLACES / 2 - precision);
402            Decimal(inner.isqrt().checked_mul(outer_mul).unwrap())
403        })
404    }
405
406    #[must_use = "this returns the result of the operation, without modifying the original"]
407    pub const fn abs_diff(self, other: Self) -> Self {
408        Self(self.0.abs_diff(other.0))
409    }
410
411    #[must_use = "this returns the result of the operation, without modifying the original"]
412    pub fn saturating_add(self, other: Self) -> Self {
413        self.checked_add(other).unwrap_or(Self::MAX)
414    }
415
416    #[must_use = "this returns the result of the operation, without modifying the original"]
417    pub fn saturating_sub(self, other: Self) -> Self {
418        self.checked_sub(other).unwrap_or_else(|_| Self::zero())
419    }
420
421    #[must_use = "this returns the result of the operation, without modifying the original"]
422    pub fn saturating_mul(self, other: Self) -> Self {
423        self.checked_mul(other).unwrap_or(Self::MAX)
424    }
425
426    #[must_use = "this returns the result of the operation, without modifying the original"]
427    pub fn saturating_pow(self, exp: u32) -> Self {
428        self.checked_pow(exp).unwrap_or(Self::MAX)
429    }
430
431    /// Converts this decimal to an unsigned integer by truncating
432    /// the fractional part, e.g. 22.5 becomes 22.
433    ///
434    /// ## Examples
435    ///
436    /// ```
437    /// use core::str::FromStr;
438    /// use cosmwasm_std::{Decimal, Uint128};
439    ///
440    /// let d = Decimal::from_str("12.345").unwrap();
441    /// assert_eq!(d.to_uint_floor(), Uint128::new(12));
442    ///
443    /// let d = Decimal::from_str("12.999").unwrap();
444    /// assert_eq!(d.to_uint_floor(), Uint128::new(12));
445    ///
446    /// let d = Decimal::from_str("75.0").unwrap();
447    /// assert_eq!(d.to_uint_floor(), Uint128::new(75));
448    /// ```
449    #[must_use = "this returns the result of the operation, without modifying the original"]
450    pub fn to_uint_floor(self) -> Uint128 {
451        self.0 / Self::DECIMAL_FRACTIONAL
452    }
453
454    /// Converts this decimal to an unsigned integer by rounding up
455    /// to the next integer, e.g. 22.3 becomes 23.
456    ///
457    /// ## Examples
458    ///
459    /// ```
460    /// use core::str::FromStr;
461    /// use cosmwasm_std::{Decimal, Uint128};
462    ///
463    /// let d = Decimal::from_str("12.345").unwrap();
464    /// assert_eq!(d.to_uint_ceil(), Uint128::new(13));
465    ///
466    /// let d = Decimal::from_str("12.999").unwrap();
467    /// assert_eq!(d.to_uint_ceil(), Uint128::new(13));
468    ///
469    /// let d = Decimal::from_str("75.0").unwrap();
470    /// assert_eq!(d.to_uint_ceil(), Uint128::new(75));
471    /// ```
472    #[must_use = "this returns the result of the operation, without modifying the original"]
473    pub fn to_uint_ceil(self) -> Uint128 {
474        // Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q
475        // from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow.
476        let x = self.0;
477        let y = Self::DECIMAL_FRACTIONAL;
478        if x.is_zero() {
479            Uint128::zero()
480        } else {
481            Uint128::one() + ((x - Uint128::one()) / y)
482        }
483    }
484}
485
486impl Fraction<Uint128> for Decimal {
487    #[inline]
488    fn numerator(&self) -> Uint128 {
489        self.0
490    }
491
492    #[inline]
493    fn denominator(&self) -> Uint128 {
494        Self::DECIMAL_FRACTIONAL
495    }
496
497    /// Returns the multiplicative inverse `1/d` for decimal `d`.
498    ///
499    /// If `d` is zero, none is returned.
500    fn inv(&self) -> Option<Self> {
501        if self.is_zero() {
502            None
503        } else {
504            // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL.
505            // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then
506            // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`.
507            Some(Decimal(Self::DECIMAL_FRACTIONAL_SQUARED / self.0))
508        }
509    }
510}
511
512impl TryFrom<Decimal256> for Decimal {
513    type Error = DecimalRangeExceeded;
514
515    fn try_from(value: Decimal256) -> Result<Self, Self::Error> {
516        value
517            .atomics()
518            .try_into()
519            .map(Decimal)
520            .map_err(|_| DecimalRangeExceeded)
521    }
522}
523
524impl TryFrom<SignedDecimal> for Decimal {
525    type Error = DecimalRangeExceeded;
526
527    fn try_from(value: SignedDecimal) -> Result<Self, Self::Error> {
528        value
529            .atomics()
530            .try_into()
531            .map(Decimal)
532            .map_err(|_| DecimalRangeExceeded)
533    }
534}
535
536impl TryFrom<SignedDecimal256> for Decimal {
537    type Error = DecimalRangeExceeded;
538
539    fn try_from(value: SignedDecimal256) -> Result<Self, Self::Error> {
540        value
541            .atomics()
542            .try_into()
543            .map(Decimal)
544            .map_err(|_| DecimalRangeExceeded)
545    }
546}
547
548impl TryFrom<Uint128> for Decimal {
549    type Error = DecimalRangeExceeded;
550
551    #[inline]
552    fn try_from(value: Uint128) -> Result<Self, Self::Error> {
553        Self::from_atomics(value, 0)
554    }
555}
556
557impl FromStr for Decimal {
558    type Err = StdError;
559
560    /// Converts the decimal string to a Decimal
561    /// Possible inputs: "1.23", "1", "000012", "1.123000000"
562    /// Disallowed: "", ".23"
563    ///
564    /// This never performs any kind of rounding.
565    /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error.
566    fn from_str(input: &str) -> Result<Self, Self::Err> {
567        let mut parts_iter = input.split('.');
568
569        let whole_part = parts_iter.next().unwrap(); // split always returns at least one element
570        let whole = whole_part.parse::<Uint128>()?;
571        let mut atomics = whole.checked_mul(Self::DECIMAL_FRACTIONAL)?;
572
573        if let Some(fractional_part) = parts_iter.next() {
574            let fractional = fractional_part.parse::<Uint128>()?;
575            let exp = Self::DECIMAL_PLACES
576                .checked_sub(fractional_part.len() as u32)
577                .ok_or_else(|| {
578                    StdError::msg(format_args!(
579                        "Cannot parse more than {} fractional digits",
580                        Self::DECIMAL_PLACES
581                    ))
582                })?;
583            debug_assert!(exp <= Self::DECIMAL_PLACES);
584            let fractional_factor = Uint128::from(10u128.pow(exp));
585            atomics = atomics.checked_add(
586                // The inner multiplication can't overflow because
587                // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES
588                fractional.checked_mul(fractional_factor).unwrap(),
589            )?;
590        }
591
592        if parts_iter.next().is_some() {
593            return Err(StdError::msg("Unexpected number of dots").with_kind(ErrorKind::Parsing));
594        }
595
596        Ok(Decimal(atomics))
597    }
598}
599
600impl fmt::Display for Decimal {
601    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
602        let whole = (self.0) / Self::DECIMAL_FRACTIONAL;
603        let fractional = self.0.checked_rem(Self::DECIMAL_FRACTIONAL).unwrap();
604
605        if fractional.is_zero() {
606            write!(f, "{whole}")
607        } else {
608            let fractional_string = format!(
609                "{:0>padding$}",
610                fractional,
611                padding = Self::DECIMAL_PLACES as usize
612            );
613            f.write_str(&whole.to_string())?;
614            f.write_char('.')?;
615            f.write_str(fractional_string.trim_end_matches('0'))?;
616            Ok(())
617        }
618    }
619}
620
621impl fmt::Debug for Decimal {
622    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
623        write!(f, "Decimal({self})")
624    }
625}
626
627impl Add for Decimal {
628    type Output = Self;
629
630    fn add(self, other: Self) -> Self {
631        Decimal(self.0 + other.0)
632    }
633}
634forward_ref_binop!(impl Add, add for Decimal, Decimal);
635
636impl AddAssign for Decimal {
637    fn add_assign(&mut self, rhs: Decimal) {
638        *self = *self + rhs;
639    }
640}
641forward_ref_op_assign!(impl AddAssign, add_assign for Decimal, Decimal);
642
643impl Sub for Decimal {
644    type Output = Self;
645
646    fn sub(self, other: Self) -> Self {
647        Decimal(self.0 - other.0)
648    }
649}
650forward_ref_binop!(impl Sub, sub for Decimal, Decimal);
651
652impl SubAssign for Decimal {
653    fn sub_assign(&mut self, rhs: Decimal) {
654        *self = *self - rhs;
655    }
656}
657forward_ref_op_assign!(impl SubAssign, sub_assign for Decimal, Decimal);
658
659impl Mul for Decimal {
660    type Output = Self;
661
662    #[allow(clippy::suspicious_arithmetic_impl)]
663    fn mul(self, other: Self) -> Self {
664        // Decimals are fractions. We can multiply two decimals a and b
665        // via
666        //       (a.numerator() * b.numerator()) / (a.denominator() * b.denominator())
667        //     = (a.numerator() * b.numerator()) / a.denominator() / b.denominator()
668
669        let result_as_uint256 = self.numerator().full_mul(other.numerator())
670            / Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); // from_uint128 is a const method and should be "free"
671        match result_as_uint256.try_into() {
672            Ok(result) => Self(result),
673            Err(_) => panic!("attempt to multiply with overflow"),
674        }
675    }
676}
677forward_ref_binop!(impl Mul, mul for Decimal, Decimal);
678
679impl MulAssign for Decimal {
680    fn mul_assign(&mut self, rhs: Decimal) {
681        *self = *self * rhs;
682    }
683}
684forward_ref_op_assign!(impl MulAssign, mul_assign for Decimal, Decimal);
685
686impl Div for Decimal {
687    type Output = Self;
688
689    fn div(self, other: Self) -> Self {
690        match Decimal::checked_from_ratio(self.numerator(), other.numerator()) {
691            Ok(ratio) => ratio,
692            Err(CheckedFromRatioError::DivideByZero) => {
693                panic!("Division failed - denominator must not be zero")
694            }
695            Err(CheckedFromRatioError::Overflow) => {
696                panic!("Division failed - multiplication overflow")
697            }
698        }
699    }
700}
701forward_ref_binop!(impl Div, div for Decimal, Decimal);
702
703impl DivAssign for Decimal {
704    fn div_assign(&mut self, rhs: Decimal) {
705        *self = *self / rhs;
706    }
707}
708forward_ref_op_assign!(impl DivAssign, div_assign for Decimal, Decimal);
709
710impl Div<Uint128> for Decimal {
711    type Output = Self;
712
713    fn div(self, rhs: Uint128) -> Self::Output {
714        Decimal(self.0 / rhs)
715    }
716}
717
718impl DivAssign<Uint128> for Decimal {
719    fn div_assign(&mut self, rhs: Uint128) {
720        self.0 /= rhs;
721    }
722}
723
724impl Rem for Decimal {
725    type Output = Self;
726
727    /// # Panics
728    ///
729    /// This operation will panic if `rhs` is zero
730    #[inline]
731    fn rem(self, rhs: Self) -> Self {
732        Self(self.0.rem(rhs.0))
733    }
734}
735forward_ref_binop!(impl Rem, rem for Decimal, Decimal);
736
737impl RemAssign<Decimal> for Decimal {
738    fn rem_assign(&mut self, rhs: Decimal) {
739        *self = *self % rhs;
740    }
741}
742forward_ref_op_assign!(impl RemAssign, rem_assign for Decimal, Decimal);
743
744impl<A> core::iter::Sum<A> for Decimal
745where
746    Self: Add<A, Output = Self>,
747{
748    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
749        iter.fold(Self::zero(), Add::add)
750    }
751}
752
753/// Serializes as a decimal string
754impl Serialize for Decimal {
755    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
756    where
757        S: ser::Serializer,
758    {
759        serializer.serialize_str(&self.to_string())
760    }
761}
762
763/// Deserializes as a base64 string
764impl<'de> Deserialize<'de> for Decimal {
765    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
766    where
767        D: Deserializer<'de>,
768    {
769        deserializer.deserialize_str(DecimalVisitor)
770    }
771}
772
773struct DecimalVisitor;
774
775impl de::Visitor<'_> for DecimalVisitor {
776    type Value = Decimal;
777
778    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
779        formatter.write_str("expected string-encoded decimal")
780    }
781
782    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
783    where
784        E: de::Error,
785    {
786        match Decimal::from_str(v) {
787            Ok(d) => Ok(d),
788            Err(e) => Err(E::custom(format_args!("Error parsing decimal '{v}': {e}"))),
789        }
790    }
791}