namada_core/
token.rs

1//! A basic fungible token
2
3use std::cmp::Ordering;
4use std::fmt::Display;
5use std::str::FromStr;
6
7use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
8use data_encoding::BASE32HEX_NOPAD;
9use ethabi::ethereum_types::U256;
10use ibc::apps::transfer::types::Amount as IbcAmount;
11use namada_macros::BorshDeserializer;
12#[cfg(feature = "migrations")]
13use namada_migrations::*;
14use serde::{Deserialize, Serialize};
15use thiserror::Error;
16
17use crate::arith::{self, CheckedAdd, CheckedSub, One, Zero, checked};
18use crate::dec::{Dec, POS_DECIMAL_PRECISION};
19use crate::storage;
20use crate::storage::{DbKeySeg, KeySeg};
21use crate::uint::{self, I256, Uint};
22
23/// Amount in micro units. For different granularity another representation
24/// might be more appropriate.
25#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
26#[derive(
27    Clone,
28    Copy,
29    Default,
30    BorshSerialize,
31    BorshDeserialize,
32    BorshDeserializer,
33    BorshSchema,
34    PartialEq,
35    Eq,
36    PartialOrd,
37    Ord,
38    Debug,
39    Hash,
40)]
41pub struct Amount {
42    raw: Uint,
43}
44
45/// Maximum decimal places in a native token [`Amount`] and [`Change`].
46/// For non-native (e.g. ERC20 tokens) one must read the `denom_key` storage
47/// key.
48pub const NATIVE_MAX_DECIMAL_PLACES: u8 = 6;
49
50/// Decimal scale of a native token [`Amount`] and [`Change`].
51/// For non-native (e.g. ERC20 tokens) one must read the `denom_key` storage
52/// key.
53pub const NATIVE_SCALE: u64 = 1_000_000;
54
55/// A change in tokens amount
56pub type Change = I256;
57
58impl Amount {
59    /// Iterate over all words in this [`Amount`].
60    pub fn iter_words(self) -> impl Iterator<Item = u64> {
61        self.raw.0.into_iter()
62    }
63
64    /// Convert a [`u64`] to an [`Amount`].
65    pub const fn from_u64(x: u64) -> Self {
66        Self {
67            raw: Uint::from_u64(x),
68        }
69    }
70
71    /// Convert a [`u128`] to an [`Amount`].
72    pub const fn from_u128(value: u128) -> Self {
73        let mut ret = [0; 4];
74        #[allow(clippy::cast_possible_truncation)]
75        {
76            ret[0] = value as u64;
77        }
78        ret[1] = (value >> 64) as u64;
79        Self { raw: Uint(ret) }
80    }
81
82    /// Get the amount as a [`Change`]
83    pub fn change(&self) -> Change {
84        self.raw.try_into().unwrap()
85    }
86
87    /// Spend a given amount.
88    pub fn spend(&mut self, amount: &Amount) -> Result<(), AmountError> {
89        self.raw = self
90            .raw
91            .checked_sub(amount.raw)
92            .ok_or(AmountError::Insufficient)?;
93        Ok(())
94    }
95
96    /// Check if there are enough funds.
97    pub fn can_spend(&self, amount: &Amount) -> bool {
98        self.raw >= amount.raw
99    }
100
101    /// Receive a given amount.
102    pub fn receive(&mut self, amount: &Amount) -> Result<(), AmountError> {
103        self.raw = self
104            .raw
105            .checked_add(amount.raw)
106            .ok_or(AmountError::Overflow)?;
107        Ok(())
108    }
109
110    /// Create a new amount of native token from whole number of tokens
111    pub fn native_whole(amount: u64) -> Self {
112        let raw = Uint::from(amount)
113            .checked_mul(Uint::from(NATIVE_SCALE))
114            .expect("u64 cannot overflow token amount");
115        Self { raw }
116    }
117
118    /// Get the raw [`Uint`] value, which represents namnam
119    pub fn raw_amount(&self) -> Uint {
120        self.raw
121    }
122
123    /// Create a new amount with the maximum value
124    pub fn max() -> Self {
125        Self {
126            raw: uint::MAX_VALUE,
127        }
128    }
129
130    /// Create a new amount with the maximum signed value
131    pub fn max_signed() -> Self {
132        Self {
133            raw: uint::MAX_SIGNED_VALUE,
134        }
135    }
136
137    /// Zero [`Amount`].
138    pub fn zero() -> Self {
139        Self::default()
140    }
141
142    /// Check if [`Amount`] is zero.
143    pub fn is_zero(&self) -> bool {
144        self.raw == Uint::from(0)
145    }
146
147    /// Check if [`Amount`] is greater than zero.
148    pub fn is_positive(&self) -> bool {
149        !self.is_zero()
150    }
151
152    /// Checked addition. Returns `None` on overflow or if
153    /// the amount exceed [`uint::MAX_VALUE`]
154    #[must_use]
155    pub fn checked_add(&self, amount: Amount) -> Option<Self> {
156        self.raw.checked_add(amount.raw).and_then(|result| {
157            if result <= uint::MAX_VALUE {
158                Some(Self { raw: result })
159            } else {
160                None
161            }
162        })
163    }
164
165    /// Checked addition. Returns `None` on overflow or if
166    /// the amount exceed [`uint::MAX_SIGNED_VALUE`]
167    #[must_use]
168    pub fn checked_signed_add(&self, amount: Amount) -> Option<Self> {
169        self.raw.checked_add(amount.raw).and_then(|result| {
170            if result <= uint::MAX_SIGNED_VALUE {
171                Some(Self { raw: result })
172            } else {
173                None
174            }
175        })
176    }
177
178    /// Checked subtraction. Returns `None` on underflow.
179    #[must_use]
180    pub fn checked_sub(&self, amount: Amount) -> Option<Self> {
181        self.raw
182            .checked_sub(amount.raw)
183            .map(|result| Self { raw: result })
184    }
185
186    /// Create amount from the absolute value of `Change`.
187    pub fn from_change(change: Change) -> Self {
188        Self { raw: change.abs() }
189    }
190
191    /// Checked division. Returns `None` on underflow.
192    #[must_use]
193    pub fn checked_div(&self, amount: Amount) -> Option<Self> {
194        self.raw
195            .checked_div(amount.raw)
196            .map(|result| Self { raw: result })
197    }
198
199    /// Checked multiplication. Returns `None` on overflow.
200    #[must_use]
201    pub fn checked_mul<T>(&self, amount: T) -> Option<Self>
202    where
203        T: Into<Self>,
204    {
205        self.raw
206            .checked_mul(amount.into().raw)
207            .map(|result| Self { raw: result })
208    }
209
210    /// Given a string and a denomination, parse an amount from string.
211    pub fn from_str(
212        string: impl AsRef<str>,
213        denom: impl Into<u8>,
214    ) -> Result<Amount, AmountParseError> {
215        DenominatedAmount::from_str(string.as_ref())?.scale(denom)
216    }
217
218    /// Attempt to convert an unsigned integer to an `Amount` with the
219    /// specified precision.
220    pub fn from_uint(
221        uint: impl Into<Uint>,
222        denom: impl Into<u8>,
223    ) -> Result<Self, AmountParseError> {
224        let denom = denom.into();
225        let uint = uint.into();
226        if denom == 0 {
227            return Ok(uint.into());
228        }
229        match Uint::from(10)
230            .checked_pow(Uint::from(denom))
231            .and_then(|scaling| scaling.checked_mul(uint))
232        {
233            Some(amount) => Ok(Self { raw: amount }),
234            None => Err(AmountParseError::ConvertToDecimal),
235        }
236    }
237
238    /// Given a u64 and [`MaspDigitPos`], construct the corresponding
239    /// amount.
240    pub fn from_masp_denominated(val: u64, denom: MaspDigitPos) -> Self {
241        let mut raw = [0u64; 4];
242        raw[denom as usize] = val;
243        Self { raw: Uint(raw) }
244    }
245
246    /// Given a i128 and [`MaspDigitPos`], construct the corresponding
247    /// amount.
248    pub fn from_masp_denominated_i128(
249        val: i128,
250        denom: MaspDigitPos,
251    ) -> Option<Self> {
252        #[allow(clippy::cast_sign_loss)]
253        #[allow(clippy::cast_possible_truncation)]
254        let lo = val as u64;
255        #[allow(clippy::cast_sign_loss)]
256        let hi = (val >> 64) as u64;
257        let lo_pos = denom as usize;
258        let hi_pos = lo_pos.checked_add(1)?;
259        let mut raw = [0u64; 4];
260        raw[lo_pos] = lo;
261        if hi != 0 && hi_pos >= 4 {
262            return None;
263        } else if hi != 0 {
264            raw[hi_pos] = hi;
265        }
266        Some(Self { raw: Uint(raw) })
267    }
268
269    /// Get a string representation of a native token amount.
270    pub fn to_string_native(&self) -> String {
271        DenominatedAmount {
272            amount: *self,
273            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
274        }
275        .to_string_precise()
276    }
277
278    /// Return a denominated native token amount.
279    #[inline]
280    pub const fn native_denominated(self) -> DenominatedAmount {
281        DenominatedAmount::native(self)
282    }
283
284    /// Convert to an [`Amount`] under the assumption that the input
285    /// string encodes all necessary decimal places.
286    pub fn from_string_precise(string: &str) -> Result<Self, AmountParseError> {
287        DenominatedAmount::from_str(string).map(|den| den.amount)
288    }
289
290    /// Multiply by a decimal [`Dec`] with the result rounded up. Returns an
291    /// error if the dec is negative. Checks for overflow.
292    pub fn mul_ceil(&self, dec: Dec) -> Result<Self, arith::Error> {
293        // Fails if the dec negative
294        let _ = checked!(Dec(I256::maximum()) - dec)?;
295
296        let tot = checked!(self.raw * dec.abs())?;
297        let denom = Uint::from(10u64.pow(u32::from(POS_DECIMAL_PRECISION)));
298        let floor_div = checked!(tot / denom)?;
299        let rem = checked!(tot % denom)?;
300        // dbg!(tot, denom, floor_div, rem);
301        let raw = if !rem.is_zero() {
302            checked!(floor_div + Uint::one())?
303        } else {
304            floor_div
305        };
306        Ok(Self { raw })
307    }
308
309    /// Multiply by a decimal [`Dec`] with the result rounded down. Returns an
310    /// error if the dec is negative. Checks for overflow.
311    pub fn mul_floor(&self, dec: Dec) -> Result<Self, arith::Error> {
312        // Fails if the dec negative
313        let _ = checked!(Dec(I256::maximum()) - dec)?;
314
315        let raw = checked!(
316            (Uint::from(*self) * dec.0.abs())
317                / Uint::from(10u64.pow(u32::from(POS_DECIMAL_PRECISION)))
318        )?;
319        Ok(Self { raw })
320    }
321
322    /// Sum with overflow check
323    pub fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Option<Self> {
324        iter.try_fold(Amount::zero(), |acc, amt| acc.checked_add(amt))
325    }
326
327    /// Divide by `u64` with zero divisor and overflow check.
328    pub fn checked_div_u64(self, rhs: u64) -> Option<Self> {
329        if rhs == 0 {
330            return None;
331        }
332        let raw = self.raw.checked_div(Uint::from(rhs))?;
333        Some(Self { raw })
334    }
335
336    /// A combination of Euclidean division and fractions:
337    /// x*(a,b) = (a*(x//b), x%b).
338    pub fn u128_eucl_div_rem(
339        mut self,
340        (a, b): (u128, u128),
341    ) -> Option<(Amount, Amount)> {
342        let a = Uint::from(a);
343        let b = Uint::from(b);
344        let raw = (self.raw.checked_div(b))?.checked_mul(a)?;
345        let amt = Amount { raw };
346        self.raw = self.raw.checked_rem(b)?;
347        Some((amt, self))
348    }
349}
350
351impl Zero for Amount {
352    fn zero() -> Self {
353        Self { raw: uint::ZERO }
354    }
355
356    fn is_zero(&self) -> bool {
357        self.raw == uint::ZERO
358    }
359}
360
361impl One for Amount {
362    fn one() -> Self {
363        Self { raw: uint::ONE }
364    }
365
366    fn is_one(&self) -> bool {
367        self.raw == uint::ONE
368    }
369}
370
371impl CheckedAdd for Amount {
372    type Output = Amount;
373
374    fn checked_add(self, rhs: Self) -> Option<Self::Output> {
375        Amount::checked_add(&self, rhs)
376    }
377}
378
379impl CheckedAdd for &Amount {
380    type Output = Amount;
381
382    fn checked_add(self, rhs: Self) -> Option<Self::Output> {
383        self.checked_add(*rhs)
384    }
385}
386
387impl CheckedSub for Amount {
388    type Output = Amount;
389
390    fn checked_sub(self, amount: Self) -> Option<Self::Output> {
391        self.raw
392            .checked_sub(amount.raw)
393            .map(|result| Self { raw: result })
394    }
395}
396
397impl CheckedSub for &Amount {
398    type Output = Amount;
399
400    fn checked_sub(self, amount: Self) -> Option<Self::Output> {
401        self.raw
402            .checked_sub(amount.raw)
403            .map(|result| Amount { raw: result })
404    }
405}
406
407impl Display for Amount {
408    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409        write!(f, "{}", self.raw)
410    }
411}
412
413/// Given a number represented as `M*B^D`, then
414/// `M` is the matissa, `B` is the base and `D`
415/// is the denomination, represented by this struct.
416#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
417#[derive(
418    Debug,
419    Copy,
420    Clone,
421    Hash,
422    PartialEq,
423    Eq,
424    PartialOrd,
425    Ord,
426    BorshSerialize,
427    BorshDeserialize,
428    BorshDeserializer,
429    BorshSchema,
430    Serialize,
431    Deserialize,
432)]
433#[serde(transparent)]
434pub struct Denomination(pub u8);
435
436impl From<u8> for Denomination {
437    fn from(denom: u8) -> Self {
438        Self(denom)
439    }
440}
441
442impl From<Denomination> for u8 {
443    fn from(denom: Denomination) -> Self {
444        denom.0
445    }
446}
447
448/// An amount with its denomination.
449#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
450#[derive(
451    Debug,
452    Copy,
453    Clone,
454    Hash,
455    PartialEq,
456    Eq,
457    BorshSerialize,
458    BorshDeserialize,
459    BorshDeserializer,
460    BorshSchema,
461)]
462pub struct DenominatedAmount {
463    /// The mantissa
464    amount: Amount,
465    /// The number of decimal places in base ten.
466    denom: Denomination,
467}
468
469impl DenominatedAmount {
470    /// Make a new denominated amount representing amount*10^(-denom)
471    pub const fn new(amount: Amount, denom: Denomination) -> Self {
472        Self { amount, denom }
473    }
474
475    /// Return a denominated native token amount.
476    pub const fn native(amount: Amount) -> Self {
477        Self {
478            amount,
479            denom: Denomination(NATIVE_MAX_DECIMAL_PLACES),
480        }
481    }
482
483    /// Check if the inner [`Amount`] is zero.
484    #[inline]
485    pub fn is_zero(&self) -> bool {
486        self.amount.is_zero()
487    }
488
489    /// A precise string representation. The number of
490    /// decimal places in this string gives the denomination.
491    /// This not true of the string produced by the `Display`
492    /// trait.
493    pub fn to_string_precise(&self) -> String {
494        let decimals = self.denom.0 as usize;
495        let mut string = self.amount.raw.to_string();
496        // escape hatch if there are no decimal places
497        if decimals == 0 {
498            return string;
499        }
500        if string.len() > decimals {
501            // Cannot underflow cause `string.len` > `decimals`
502            #[allow(clippy::arithmetic_side_effects)]
503            let idx = string.len() - decimals;
504            string.insert(idx, '.');
505        } else {
506            for _ in string.len()..decimals {
507                string.insert(0, '0');
508            }
509            string.insert(0, '.');
510            string.insert(0, '0');
511        }
512        string
513    }
514
515    /// Find the minimal precision that holds this value losslessly.
516    /// This equates to stripping trailing zeros after the decimal
517    /// place.
518    pub fn canonical(self) -> Self {
519        let mut value = self.amount.raw;
520        let ten = Uint::from(10);
521        let mut denom = self.denom.0;
522        for _ in 0..self.denom.0 {
523            let (div, rem) = value.div_mod(ten);
524            if rem == Uint::zero() {
525                value = div;
526                denom = denom.checked_sub(1).unwrap_or_default();
527            }
528        }
529        Self {
530            amount: Amount { raw: value },
531            denom: denom.into(),
532        }
533    }
534
535    /// Return an equivalent denominated amount with the given denomination. Can
536    /// fail if the resulting amount does not fit into 256 bits.
537    pub fn increase_precision(
538        self,
539        denom: Denomination,
540    ) -> Result<Self, AmountParseError> {
541        if denom.0 < self.denom.0 {
542            return Err(AmountParseError::PrecisionDecrease);
543        }
544        // Cannot underflow cause `denom` >= `self.denom`
545        #[allow(clippy::arithmetic_side_effects)]
546        let denom_diff = denom.0 - self.denom.0;
547        Uint::from(10)
548            .checked_pow(Uint::from(denom_diff))
549            .and_then(|scaling| self.amount.raw.checked_mul(scaling))
550            .map(|amount| Self {
551                amount: Amount { raw: amount },
552                denom,
553            })
554            .ok_or(AmountParseError::PrecisionOverflow)
555    }
556
557    /// Return the closest denominated amount with the given denomination and
558    /// the error.
559    pub fn approximate(
560        self,
561        denom: Denomination,
562    ) -> Result<(Self, Self), AmountParseError> {
563        if denom.0 < self.denom.0 {
564            // Divide numerator and denominator by a power of 10
565            let amount = self.amount.raw_amount();
566            #[allow(clippy::arithmetic_side_effects)]
567            let (quot, rem) = Uint::from(10)
568                .checked_pow(Uint::from(self.denom.0 - denom.0))
569                .and_then(|scaling| {
570                    amount.checked_div(scaling).zip(amount.checked_rem(scaling))
571                })
572                .ok_or(AmountParseError::PrecisionOverflow)?;
573            let approx = Self {
574                amount: quot.into(),
575                denom,
576            };
577            let error = Self {
578                amount: rem.into(),
579                denom: self.denom,
580            };
581            Ok((approx, error))
582        } else {
583            // Multiply numerator and denominator by a power of 10
584            let error = Self {
585                amount: 0.into(),
586                denom: self.denom,
587            };
588            self.increase_precision(denom).map(|x| (x, error))
589        }
590    }
591
592    /// Create a new [`DenominatedAmount`] with the same underlying
593    /// amount but a new denomination.
594    pub fn redenominate(self, new_denom: u8) -> Self {
595        Self {
596            amount: self.amount,
597            denom: new_denom.into(),
598        }
599    }
600
601    /// Multiply this number by 10^denom and return the computed integer if
602    /// possible. Otherwise error out.
603    pub fn scale(
604        self,
605        denom: impl Into<u8>,
606    ) -> Result<Amount, AmountParseError> {
607        self.increase_precision(Denomination(denom.into()))
608            .map(|x| x.amount)
609    }
610
611    /// Checked multiplication. Returns `None` on overflow.
612    pub fn checked_mul(&self, rhs: DenominatedAmount) -> Option<Self> {
613        let amount = self.amount.checked_mul(rhs.amount)?;
614        let denom = self.denom.0.checked_add(rhs.denom.0)?.into();
615        Some(Self { amount, denom })
616    }
617
618    /// Checked subtraction. Returns `None` on overflow.
619    pub fn checked_sub(&self, mut rhs: DenominatedAmount) -> Option<Self> {
620        let mut lhs = *self;
621        if lhs.denom < rhs.denom {
622            lhs = lhs.increase_precision(rhs.denom).ok()?;
623        } else {
624            rhs = rhs.increase_precision(lhs.denom).ok()?;
625        }
626        let amount = lhs.amount.checked_sub(rhs.amount)?;
627        Some(Self {
628            amount,
629            denom: lhs.denom,
630        })
631    }
632
633    /// Checked addition. Returns `None` on overflow.
634    pub fn checked_add(&self, mut rhs: DenominatedAmount) -> Option<Self> {
635        let mut lhs = *self;
636        if lhs.denom < rhs.denom {
637            lhs = lhs.increase_precision(rhs.denom).ok()?;
638        } else {
639            rhs = rhs.increase_precision(lhs.denom).ok()?;
640        }
641        let amount = lhs.amount.checked_add(rhs.amount)?;
642        Some(Self {
643            amount,
644            denom: lhs.denom,
645        })
646    }
647
648    /// Checked division computed to the given precision. Returns `None` on
649    /// overflow.
650    pub fn checked_div_precision(
651        &self,
652        rhs: DenominatedAmount,
653        denom: Denomination,
654    ) -> Option<Self> {
655        #[allow(clippy::arithmetic_side_effects)]
656        let pow = i16::from(rhs.denom.0) + i16::from(denom.0)
657            - i16::from(self.denom.0);
658        if pow < 0 {
659            return None;
660        }
661        let amount = Uint::from(10).checked_pow(Uint::from(pow)).and_then(
662            |scaling| {
663                scaling.checked_mul_div(
664                    self.amount.raw_amount(),
665                    rhs.amount.raw_amount(),
666                )
667            },
668        )?;
669        Some(Self {
670            amount: amount.0.into(),
671            denom,
672        })
673    }
674
675    /// Checked division. Returns `None` on overflow.
676    pub fn checked_div(&self, rhs: DenominatedAmount) -> Option<Self> {
677        self.checked_div_precision(rhs, self.denom)
678    }
679
680    /// Returns the significand of this number
681    pub const fn amount(&self) -> Amount {
682        self.amount
683    }
684
685    /// Returns the denomination of this number
686    pub const fn denom(&self) -> Denomination {
687        self.denom
688    }
689}
690
691impl Display for DenominatedAmount {
692    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
693        let string = self.to_string_precise();
694        let string = if self.denom.0 > 0 {
695            string.trim_end_matches(['0'])
696        } else {
697            &string
698        };
699        let string = string.trim_end_matches(['.']);
700        f.write_str(string)
701    }
702}
703
704impl FromStr for DenominatedAmount {
705    type Err = AmountParseError;
706
707    fn from_str(s: &str) -> Result<Self, Self::Err> {
708        let precision = s.find('.').map(|pos| {
709            s.len()
710                .checked_sub(pos.checked_add(1).unwrap_or(pos))
711                .unwrap_or_default()
712        });
713        let digits = s
714            .chars()
715            .filter_map(|c| {
716                if c.is_numeric() {
717                    c.to_digit(10).map(Uint::from)
718                } else {
719                    None
720                }
721            })
722            .rev()
723            .collect::<Vec<_>>();
724        if digits.len() != s.len() && precision.is_none()
725            || digits.len() != s.len().checked_sub(1).unwrap_or_default()
726                && precision.is_some()
727        {
728            return Err(AmountParseError::NotNumeric);
729        }
730        if digits.len() > 77 {
731            return Err(AmountParseError::ScaleTooLarge(digits.len(), 77));
732        }
733        let mut value = Uint::default();
734        let ten = Uint::from(10);
735        for (pow, digit) in digits.into_iter().enumerate() {
736            value = ten
737                .checked_pow(Uint::from(pow))
738                .and_then(|scaling| scaling.checked_mul(digit))
739                .and_then(|scaled| value.checked_add(scaled))
740                .ok_or(AmountParseError::InvalidRange)?;
741        }
742        let denom = Denomination(
743            u8::try_from(precision.unwrap_or_default())
744                .map_err(|_e| AmountParseError::PrecisionOverflow)?,
745        );
746        Ok(Self {
747            amount: Amount { raw: value },
748            denom,
749        })
750    }
751}
752
753impl PartialOrd for DenominatedAmount {
754    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
755        Some(self.cmp(other))
756    }
757}
758
759impl Ord for DenominatedAmount {
760    fn cmp(&self, other: &Self) -> Ordering {
761        if self.amount.is_zero() && other.is_zero() {
762            Ordering::Equal
763        } else if self.amount.is_zero() {
764            Ordering::Less
765        } else if other.amount.is_zero() {
766            Ordering::Greater
767        } else if self.denom < other.denom {
768            // Cannot underflow cause `self.denom` < `other.denom`
769            #[allow(clippy::arithmetic_side_effects)]
770            let diff = other.denom.0 - self.denom.0;
771            if diff > 77 {
772                // This branch catches case where exponentiation overflows
773                return Ordering::Greater;
774            }
775            let (div, rem) =
776                other.amount.raw.div_mod(Uint::exp10(diff as usize));
777            let div_ceil = if rem.is_zero() {
778                div
779            } else {
780                div.checked_add(Uint::one()).unwrap_or(Uint::MAX)
781            };
782            let ord = self.amount.raw.cmp(&div_ceil);
783            if let Ordering::Equal = ord {
784                if rem.is_zero() {
785                    Ordering::Equal
786                } else {
787                    Ordering::Greater
788                }
789            } else {
790                ord
791            }
792        } else {
793            // Cannot underflow cause `other.denom` >= `self.denom`
794            #[allow(clippy::arithmetic_side_effects)]
795            let diff = self.denom.0 - other.denom.0;
796            if diff > 77 {
797                // This branch catches case where exponentiation overflows
798                return Ordering::Less;
799            }
800            let (div, rem) =
801                self.amount.raw.div_mod(Uint::exp10(diff as usize));
802            let div_ceil = if rem.is_zero() {
803                div
804            } else {
805                div.checked_add(Uint::one()).unwrap_or(Uint::MAX)
806            };
807            let ord = div_ceil.cmp(&other.amount.raw);
808            if let Ordering::Equal = ord {
809                if rem.is_zero() {
810                    Ordering::Equal
811                } else {
812                    Ordering::Less
813                }
814            } else {
815                ord
816            }
817        }
818    }
819}
820
821impl serde::Serialize for Amount {
822    fn serialize<S>(
823        &self,
824        serializer: S,
825    ) -> std::result::Result<S::Ok, S::Error>
826    where
827        S: serde::Serializer,
828    {
829        let amount_string = self.raw.to_string();
830        serde::Serialize::serialize(&amount_string, serializer)
831    }
832}
833
834impl<'de> serde::Deserialize<'de> for Amount {
835    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
836    where
837        D: serde::Deserializer<'de>,
838    {
839        let amount_string: String =
840            serde::Deserialize::deserialize(deserializer)?;
841        let amt = DenominatedAmount::from_str(&amount_string).unwrap();
842        Ok(amt.amount)
843    }
844}
845
846impl serde::Serialize for DenominatedAmount {
847    fn serialize<S>(
848        &self,
849        serializer: S,
850    ) -> std::result::Result<S::Ok, S::Error>
851    where
852        S: serde::Serializer,
853    {
854        let amount_string = self.to_string_precise();
855        serde::Serialize::serialize(&amount_string, serializer)
856    }
857}
858
859impl<'de> serde::Deserialize<'de> for DenominatedAmount {
860    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
861    where
862        D: serde::Deserializer<'de>,
863    {
864        use serde::de::Error;
865        let amount_string: String =
866            serde::Deserialize::deserialize(deserializer)?;
867        Self::from_str(&amount_string).map_err(D::Error::custom)
868    }
869}
870
871impl From<Amount> for DenominatedAmount {
872    fn from(amount: Amount) -> Self {
873        DenominatedAmount::new(amount, 0.into())
874    }
875}
876
877// Treats the u64 as a value of the raw amount (namnam)
878impl From<u64> for Amount {
879    fn from(val: u64) -> Amount {
880        Amount {
881            raw: Uint::from(val),
882        }
883    }
884}
885
886impl From<Amount> for U256 {
887    fn from(amt: Amount) -> Self {
888        Self(amt.raw.0)
889    }
890}
891
892impl TryFrom<Dec> for Amount {
893    type Error = arith::Error;
894
895    fn try_from(dec: Dec) -> Result<Amount, Self::Error> {
896        // Fails if the dec negative
897        let _ = checked!(Dec(I256::maximum()) - dec)?;
898
899        // Division cannot panic as divisor is non-zero
900        #[allow(clippy::arithmetic_side_effects)]
901        let raw = dec.0.abs() / Uint::exp10(POS_DECIMAL_PRECISION as usize);
902        Ok(Amount { raw })
903    }
904}
905
906impl TryFrom<Amount> for u128 {
907    type Error = std::io::Error;
908
909    fn try_from(value: Amount) -> Result<Self, Self::Error> {
910        let Uint(arr) = value.raw;
911        for word in arr.iter().skip(2) {
912            if *word != 0 {
913                return Err(std::io::Error::new(
914                    std::io::ErrorKind::InvalidInput,
915                    "Integer overflow when casting to u128",
916                ));
917            }
918        }
919        Ok(value.raw.low_u128())
920    }
921}
922
923impl KeySeg for Amount {
924    fn parse(string: String) -> super::storage::Result<Self>
925    where
926        Self: Sized,
927    {
928        let bytes = BASE32HEX_NOPAD.decode(string.as_ref()).map_err(|err| {
929            storage::Error::ParseKeySeg(format!(
930                "Failed parsing {} with {}",
931                string, err
932            ))
933        })?;
934        Ok(Amount {
935            raw: Uint::from_big_endian(&bytes),
936        })
937    }
938
939    fn raw(&self) -> String {
940        let buf = self.raw.to_big_endian();
941        BASE32HEX_NOPAD.encode(&buf)
942    }
943
944    fn to_db_key(&self) -> DbKeySeg {
945        DbKeySeg::StringSeg(self.raw())
946    }
947}
948
949#[allow(missing_docs)]
950#[derive(Error, Debug)]
951pub enum AmountParseError {
952    #[error(
953        "Error decoding token amount, too many decimal places: {0}. Maximum \
954         {1}"
955    )]
956    ScaleTooLarge(usize, u8),
957    #[error(
958        "Error decoding token amount, the value is not within invalid range."
959    )]
960    InvalidRange,
961    #[error("Error converting amount to decimal, number too large.")]
962    ConvertToDecimal,
963    #[error(
964        "Could not convert from string, expected an unsigned 256-bit integer."
965    )]
966    FromString,
967    #[error("Could not parse string as a correctly formatted number.")]
968    NotNumeric,
969    #[error("This amount cannot handle the requested precision in 256 bits.")]
970    PrecisionOverflow,
971    #[error("More precision given in the amount than requested.")]
972    PrecisionDecrease,
973}
974
975impl From<Amount> for Change {
976    fn from(amount: Amount) -> Self {
977        amount.raw.try_into().unwrap()
978    }
979}
980
981impl From<Change> for Amount {
982    fn from(change: Change) -> Self {
983        Amount { raw: change.abs() }
984    }
985}
986
987impl From<Amount> for Uint {
988    fn from(amount: Amount) -> Self {
989        amount.raw
990    }
991}
992
993impl From<Uint> for Amount {
994    fn from(raw: Uint) -> Self {
995        Self { raw }
996    }
997}
998
999/// The four possible u64 words in a [`Uint`].
1000/// Used for converting to MASP amounts.
1001#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1002#[derive(
1003    Copy,
1004    Clone,
1005    Debug,
1006    PartialEq,
1007    Eq,
1008    PartialOrd,
1009    Ord,
1010    Hash,
1011    BorshSerialize,
1012    BorshDeserialize,
1013    BorshDeserializer,
1014    BorshSchema,
1015    Serialize,
1016    Deserialize,
1017)]
1018#[repr(u8)]
1019#[allow(missing_docs)]
1020#[borsh(use_discriminant = true)]
1021pub enum MaspDigitPos {
1022    Zero = 0,
1023    One,
1024    Two,
1025    Three,
1026}
1027
1028impl TryFrom<u8> for MaspDigitPos {
1029    type Error = &'static str;
1030
1031    fn try_from(denom: u8) -> Result<Self, Self::Error> {
1032        match denom {
1033            0 => Ok(Self::Zero),
1034            1 => Ok(Self::One),
1035            2 => Ok(Self::Two),
1036            3 => Ok(Self::Three),
1037            _ => Err("Possible MASP denominations must be between 0 and 3"),
1038        }
1039    }
1040}
1041
1042impl MaspDigitPos {
1043    /// Iterator over the possible denominations
1044    pub fn iter() -> impl Iterator<Item = MaspDigitPos> {
1045        [
1046            MaspDigitPos::Zero,
1047            MaspDigitPos::One,
1048            MaspDigitPos::Two,
1049            MaspDigitPos::Three,
1050        ]
1051        .into_iter()
1052    }
1053
1054    /// Get the corresponding u64 word from the input uint256.
1055    pub fn denominate<'a>(&self, amount: impl Into<&'a Amount>) -> u64 {
1056        let amount = amount.into();
1057        amount.raw.0[*self as usize]
1058    }
1059}
1060
1061impl From<Amount> for IbcAmount {
1062    fn from(amount: Amount) -> Self {
1063        primitive_types::U256(amount.raw.0).into()
1064    }
1065}
1066
1067impl TryFrom<IbcAmount> for Amount {
1068    type Error = AmountParseError;
1069
1070    fn try_from(amount: IbcAmount) -> Result<Self, Self::Error> {
1071        let uint = Uint(primitive_types::U256::from(amount).0);
1072        Self::from_uint(uint, 0)
1073    }
1074}
1075
1076impl From<DenominatedAmount> for IbcAmount {
1077    fn from(amount: DenominatedAmount) -> Self {
1078        amount.amount.into()
1079    }
1080}
1081
1082#[allow(missing_docs)]
1083#[derive(Error, Debug)]
1084pub enum AmountError {
1085    #[error("Insufficient amount")]
1086    Insufficient,
1087    #[error("Amount overlofow")]
1088    Overflow,
1089}
1090
1091#[cfg(any(test, feature = "testing"))]
1092/// Testing helpers and strategies for tokens
1093#[allow(clippy::arithmetic_side_effects)]
1094pub mod testing {
1095    use proptest::prelude::*;
1096
1097    use super::*;
1098
1099    impl std::ops::Add for Amount {
1100        type Output = Self;
1101
1102        fn add(self, rhs: Self) -> Self::Output {
1103            self.checked_add(rhs).unwrap()
1104        }
1105    }
1106
1107    impl std::ops::AddAssign for Amount {
1108        fn add_assign(&mut self, rhs: Self) {
1109            *self = self.checked_add(rhs).unwrap();
1110        }
1111    }
1112
1113    impl std::ops::Sub for Amount {
1114        type Output = Self;
1115
1116        fn sub(self, rhs: Self) -> Self::Output {
1117            self.checked_sub(rhs).unwrap()
1118        }
1119    }
1120
1121    impl std::ops::SubAssign for Amount {
1122        fn sub_assign(&mut self, rhs: Self) {
1123            *self = *self - rhs;
1124        }
1125    }
1126
1127    impl<T> std::ops::Mul<T> for Amount
1128    where
1129        T: Into<Self>,
1130    {
1131        type Output = Amount;
1132
1133        fn mul(self, rhs: T) -> Self::Output {
1134            self.checked_mul(rhs.into()).unwrap()
1135        }
1136    }
1137
1138    impl std::ops::Mul<Amount> for u64 {
1139        type Output = Amount;
1140
1141        fn mul(self, rhs: Amount) -> Self::Output {
1142            rhs * self
1143        }
1144    }
1145
1146    impl std::ops::Div<u64> for Amount {
1147        type Output = Self;
1148
1149        fn div(self, rhs: u64) -> Self::Output {
1150            Self {
1151                raw: self.raw / Uint::from(rhs),
1152            }
1153        }
1154    }
1155
1156    impl std::iter::Sum for Amount {
1157        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1158            iter.fold(Amount::zero(), |a, b| a + b)
1159        }
1160    }
1161
1162    prop_compose! {
1163        /// Generate an arbitrary denomination
1164        pub fn arb_denomination()(denom in 0u8..) -> Denomination {
1165            Denomination(denom)
1166        }
1167    }
1168
1169    prop_compose! {
1170        /// Generate a denominated amount
1171        pub fn arb_denominated_amount()(
1172            amount in arb_amount(),
1173            denom in arb_denomination(),
1174        ) -> DenominatedAmount {
1175            DenominatedAmount::new(amount, denom)
1176        }
1177    }
1178
1179    /// Generate an arbitrary token amount
1180    pub fn arb_amount() -> impl Strategy<Value = Amount> {
1181        any::<u64>().prop_map(|val| Amount::from_uint(val, 0).unwrap())
1182    }
1183
1184    /// Generate an arbitrary token amount up to and including given `max` value
1185    pub fn arb_amount_ceiled(max: u64) -> impl Strategy<Value = Amount> {
1186        (0..=max).prop_map(|val| Amount::from_uint(val, 0).unwrap())
1187    }
1188
1189    /// Generate an arbitrary non-zero token amount up to and including given
1190    /// `max` value
1191    pub fn arb_amount_non_zero_ceiled(
1192        max: u64,
1193    ) -> impl Strategy<Value = Amount> {
1194        (1..=max).prop_map(|val| Amount::from_uint(val, 0).unwrap())
1195    }
1196}
1197
1198#[cfg(test)]
1199mod tests {
1200    use assert_matches::assert_matches;
1201
1202    use super::*;
1203
1204    #[test]
1205    fn test_token_display() {
1206        let max = Amount::from_uint(u64::MAX, 0).expect("Test failed");
1207        assert_eq!("18446744073709.551615", max.to_string_native());
1208        let max = DenominatedAmount {
1209            amount: max,
1210            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1211        };
1212        assert_eq!("18446744073709.551615", max.to_string());
1213
1214        let whole =
1215            Amount::from_uint(u64::MAX / NATIVE_SCALE * NATIVE_SCALE, 0)
1216                .expect("Test failed");
1217        assert_eq!("18446744073709.000000", whole.to_string_native());
1218        let whole = DenominatedAmount {
1219            amount: whole,
1220            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1221        };
1222        assert_eq!("18446744073709", whole.to_string());
1223
1224        let trailing_zeroes =
1225            Amount::from_uint(123000, 0).expect("Test failed");
1226        assert_eq!("0.123000", trailing_zeroes.to_string_native());
1227        let trailing_zeroes = DenominatedAmount {
1228            amount: trailing_zeroes,
1229            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1230        };
1231        assert_eq!("0.123", trailing_zeroes.to_string());
1232
1233        let zero = Amount::default();
1234        assert_eq!("0.000000", zero.to_string_native());
1235        let zero = DenominatedAmount {
1236            amount: zero,
1237            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1238        };
1239        assert_eq!("0", zero.to_string());
1240
1241        let amount = DenominatedAmount {
1242            amount: Amount::from_uint(1120, 0).expect("Test failed"),
1243            denom: 3u8.into(),
1244        };
1245        assert_eq!("1.12", amount.to_string());
1246        assert_eq!("1.120", amount.to_string_precise());
1247
1248        let amount = DenominatedAmount {
1249            amount: Amount::from_uint(1120, 0).expect("Test failed"),
1250            denom: 5u8.into(),
1251        };
1252        assert_eq!("0.0112", amount.to_string());
1253        assert_eq!("0.01120", amount.to_string_precise());
1254
1255        let amount = DenominatedAmount {
1256            amount: Amount::from_uint(200, 0).expect("Test failed"),
1257            denom: 0.into(),
1258        };
1259        assert_eq!("200", amount.to_string());
1260        assert_eq!("200", amount.to_string_precise());
1261    }
1262
1263    #[test]
1264    fn test_amount_checked_sub() {
1265        let max = Amount::native_whole(u64::MAX);
1266        let one = Amount::native_whole(1);
1267        let zero = Amount::native_whole(0);
1268
1269        assert_eq!(zero.checked_sub(zero), Some(zero));
1270        assert_eq!(zero.checked_sub(one), None);
1271        assert_eq!(zero.checked_sub(max), None);
1272
1273        assert_eq!(max.checked_sub(zero), Some(max));
1274        assert_eq!(max.checked_sub(one), Some(max - one));
1275        assert_eq!(max.checked_sub(max), Some(zero));
1276    }
1277
1278    #[test]
1279    fn test_serialization_round_trip() {
1280        let amount: Amount = serde_json::from_str(r#""1000000000""#).unwrap();
1281        assert_eq!(
1282            amount,
1283            Amount {
1284                raw: Uint::from(1000000000)
1285            }
1286        );
1287        let serialized = serde_json::to_string(&amount).unwrap();
1288        assert_eq!(serialized, r#""1000000000""#);
1289    }
1290
1291    #[test]
1292    fn test_amount_checked_add() {
1293        let max = Amount::max();
1294        let max_signed = Amount::max_signed();
1295        let one = Amount::native_whole(1);
1296        let zero = Amount::native_whole(0);
1297
1298        assert_eq!(zero.checked_add(zero), Some(zero));
1299        assert_eq!(zero.checked_signed_add(zero), Some(zero));
1300        assert_eq!(zero.checked_add(one), Some(one));
1301        assert_eq!(zero.checked_add(max - one), Some(max - one));
1302        assert_eq!(
1303            zero.checked_signed_add(max_signed - one),
1304            Some(max_signed - one)
1305        );
1306        assert_eq!(zero.checked_add(max), Some(max));
1307        assert_eq!(zero.checked_signed_add(max_signed), Some(max_signed));
1308
1309        assert_eq!(max.checked_add(zero), Some(max));
1310        assert_eq!(max.checked_signed_add(zero), None);
1311        assert_eq!(max.checked_add(one), None);
1312        assert_eq!(max.checked_add(max), None);
1313
1314        assert_eq!(max_signed.checked_add(zero), Some(max_signed));
1315        assert_eq!(max_signed.checked_add(one), Some(max_signed + one));
1316        assert_eq!(max_signed.checked_signed_add(max_signed), None);
1317    }
1318
1319    #[test]
1320    fn test_amount_from_string() {
1321        assert!(Amount::from_str("1.12", 1).is_err());
1322        assert!(Amount::from_str("0.0", 0).is_err());
1323        assert!(Amount::from_str("1.12", 80).is_err());
1324        assert!(Amount::from_str("1.12.1", 3).is_err());
1325        assert!(Amount::from_str("1.1a", 3).is_err());
1326        assert_eq!(
1327            Amount::zero(),
1328            Amount::from_str("0.0", 1).expect("Test failed")
1329        );
1330        assert_eq!(
1331            Amount::zero(),
1332            Amount::from_str(".0", 1).expect("Test failed")
1333        );
1334
1335        let amount = Amount::from_str("1.12", 3).expect("Test failed");
1336        assert_eq!(amount, Amount::from_uint(1120, 0).expect("Test failed"));
1337        let amount = Amount::from_str(".34", 3).expect("Test failed");
1338        assert_eq!(amount, Amount::from_uint(340, 0).expect("Test failed"));
1339        let amount = Amount::from_str("0.34", 3).expect("Test failed");
1340        assert_eq!(amount, Amount::from_uint(340, 0).expect("Test failed"));
1341        let amount = Amount::from_str("34", 1).expect("Test failed");
1342        assert_eq!(amount, Amount::from_uint(340, 0).expect("Test failed"));
1343    }
1344
1345    #[test]
1346    fn test_from_masp_denominated() {
1347        let uint = Uint([15u64, 16, 17, 18]);
1348        let original = Amount::from_uint(uint, 0).expect("Test failed");
1349        for denom in MaspDigitPos::iter() {
1350            let word = denom.denominate(&original);
1351            assert_eq!(word, denom as u64 + 15u64);
1352            let amount = Amount::from_masp_denominated(word, denom);
1353            let raw = Uint::from(amount).0;
1354            let mut expected = [0u64; 4];
1355            expected[denom as usize] = word;
1356            assert_eq!(raw, expected);
1357        }
1358    }
1359
1360    #[test]
1361    fn test_key_seg() {
1362        let original = Amount::from_uint(1234560000, 0).expect("Test failed");
1363        let key = original.raw();
1364        let amount = Amount::parse(key).expect("Test failed");
1365        assert_eq!(amount, original);
1366    }
1367
1368    #[test]
1369    fn test_amount_is_zero() {
1370        let zero = Amount::zero();
1371        assert!(zero.is_zero());
1372
1373        let non_zero = Amount::from_uint(1, 0).expect("Test failed");
1374        assert!(!non_zero.is_zero());
1375    }
1376
1377    #[test]
1378    fn test_token_amount_mul_ceil() {
1379        let one = Amount::from(1);
1380        let two = Amount::from(2);
1381        let three = Amount::from(3);
1382        let dec = Dec::from_str("0.34").unwrap();
1383        assert_eq!(one.mul_ceil(dec).unwrap(), one);
1384        assert_eq!(two.mul_ceil(dec).unwrap(), one);
1385        assert_eq!(three.mul_ceil(dec).unwrap(), two);
1386
1387        assert_matches!(one.mul_ceil(-dec), Err(_));
1388        assert_matches!(one.mul_ceil(-Dec::new(1, 12).unwrap()), Err(_));
1389        assert_matches!(
1390            Amount::native_whole(1).mul_ceil(-Dec::new(1, 12).unwrap()),
1391            Err(_)
1392        );
1393    }
1394
1395    #[test]
1396    fn test_token_amount_mul_floor() {
1397        let zero = Amount::zero();
1398        let one = Amount::from(1);
1399        let two = Amount::from(2);
1400        let three = Amount::from(3);
1401        let dec = Dec::from_str("0.34").unwrap();
1402        assert_eq!(one.mul_floor(dec).unwrap(), zero);
1403        assert_eq!(two.mul_floor(dec).unwrap(), zero);
1404        assert_eq!(three.mul_floor(dec).unwrap(), one);
1405
1406        assert_matches!(one.mul_floor(-dec), Err(_));
1407        assert_matches!(one.mul_floor(-Dec::new(1, 12).unwrap()), Err(_));
1408        assert_matches!(
1409            Amount::native_whole(1).mul_floor(-Dec::new(1, 12).unwrap()),
1410            Err(_)
1411        );
1412    }
1413
1414    #[test]
1415    fn test_denominateed_arithmetic() {
1416        let a = DenominatedAmount::new(10.into(), 3.into());
1417        let b = DenominatedAmount::new(10.into(), 2.into());
1418        let c = DenominatedAmount::new(110.into(), 3.into());
1419        let d = DenominatedAmount::new(90.into(), 3.into());
1420        let e = DenominatedAmount::new(100.into(), 5.into());
1421        let f = DenominatedAmount::new(100.into(), 3.into());
1422        let g = DenominatedAmount::new(0.into(), 3.into());
1423        assert_eq!(a.checked_add(b).unwrap(), c);
1424        assert_eq!(b.checked_sub(a).unwrap(), d);
1425        assert_eq!(a.checked_mul(b).unwrap(), e);
1426        assert!(a.checked_sub(b).is_none());
1427        assert_eq!(c.checked_sub(a).unwrap(), f);
1428        assert_eq!(c.checked_sub(c).unwrap(), g);
1429    }
1430
1431    #[test]
1432    fn test_denominated_amt_ord() {
1433        let denom_1 = DenominatedAmount {
1434            amount: Amount::from_uint(15, 0).expect("Test failed"),
1435            denom: 1.into(),
1436        };
1437        let denom_2 = DenominatedAmount {
1438            amount: Amount::from_uint(1500, 0).expect("Test failed"),
1439            denom: 3.into(),
1440        };
1441        // The psychedelic case. Partial ordering works on the underlying
1442        // amounts but `Eq` also checks the equality of denoms.
1443        assert_eq!(
1444            denom_1.partial_cmp(&denom_2).expect("Test failed"),
1445            Ordering::Equal
1446        );
1447        assert_eq!(
1448            denom_2.partial_cmp(&denom_1).expect("Test failed"),
1449            Ordering::Equal
1450        );
1451        assert_ne!(denom_1, denom_2);
1452
1453        let denom_1 = DenominatedAmount {
1454            amount: Amount::from_uint(15, 0).expect("Test failed"),
1455            denom: 1.into(),
1456        };
1457        let denom_2 = DenominatedAmount {
1458            amount: Amount::from_uint(1501, 0).expect("Test failed"),
1459            denom: 3.into(),
1460        };
1461        assert_eq!(
1462            denom_1.partial_cmp(&denom_2).expect("Test failed"),
1463            Ordering::Less
1464        );
1465        assert_eq!(
1466            denom_2.partial_cmp(&denom_1).expect("Test failed"),
1467            Ordering::Greater
1468        );
1469        let denom_1 = DenominatedAmount {
1470            amount: Amount::from_uint(15, 0).expect("Test failed"),
1471            denom: 1.into(),
1472        };
1473        let denom_2 = DenominatedAmount {
1474            amount: Amount::from_uint(1499, 0).expect("Test failed"),
1475            denom: 3.into(),
1476        };
1477        assert_eq!(
1478            denom_1.partial_cmp(&denom_2).expect("Test failed"),
1479            Ordering::Greater
1480        );
1481        assert_eq!(
1482            denom_2.partial_cmp(&denom_1).expect("Test failed"),
1483            Ordering::Less
1484        );
1485    }
1486
1487    #[test]
1488    fn test_token_amount_from_u128() {
1489        for val in [
1490            u128::MIN,
1491            u128::MIN + 1,
1492            u128::from(u64::MAX) - 1,
1493            u128::from(u64::MAX),
1494            u128::from(u64::MAX) + 1,
1495            u128::MAX - 1,
1496            u128::MAX,
1497        ] {
1498            let raw = Uint::from(val);
1499            let amount = Amount::from_u128(val);
1500            assert_eq!(raw, amount.raw);
1501            assert_eq!(amount.raw.as_u128(), val);
1502        }
1503    }
1504}