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, 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 CheckedAdd for Amount {
352    type Output = Amount;
353
354    fn checked_add(self, rhs: Self) -> Option<Self::Output> {
355        Amount::checked_add(&self, rhs)
356    }
357}
358
359impl CheckedAdd for &Amount {
360    type Output = Amount;
361
362    fn checked_add(self, rhs: Self) -> Option<Self::Output> {
363        self.checked_add(*rhs)
364    }
365}
366
367impl CheckedSub for Amount {
368    type Output = Amount;
369
370    fn checked_sub(self, amount: Self) -> Option<Self::Output> {
371        self.raw
372            .checked_sub(amount.raw)
373            .map(|result| Self { raw: result })
374    }
375}
376
377impl CheckedSub for &Amount {
378    type Output = Amount;
379
380    fn checked_sub(self, amount: Self) -> Option<Self::Output> {
381        self.raw
382            .checked_sub(amount.raw)
383            .map(|result| Amount { raw: result })
384    }
385}
386
387impl Display for Amount {
388    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389        write!(f, "{}", self.raw)
390    }
391}
392
393/// Given a number represented as `M*B^D`, then
394/// `M` is the matissa, `B` is the base and `D`
395/// is the denomination, represented by this struct.
396#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
397#[derive(
398    Debug,
399    Copy,
400    Clone,
401    Hash,
402    PartialEq,
403    Eq,
404    PartialOrd,
405    Ord,
406    BorshSerialize,
407    BorshDeserialize,
408    BorshDeserializer,
409    BorshSchema,
410    Serialize,
411    Deserialize,
412)]
413#[serde(transparent)]
414pub struct Denomination(pub u8);
415
416impl From<u8> for Denomination {
417    fn from(denom: u8) -> Self {
418        Self(denom)
419    }
420}
421
422impl From<Denomination> for u8 {
423    fn from(denom: Denomination) -> Self {
424        denom.0
425    }
426}
427
428/// An amount with its denomination.
429#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
430#[derive(
431    Debug,
432    Copy,
433    Clone,
434    Hash,
435    PartialEq,
436    Eq,
437    BorshSerialize,
438    BorshDeserialize,
439    BorshDeserializer,
440    BorshSchema,
441)]
442pub struct DenominatedAmount {
443    /// The mantissa
444    amount: Amount,
445    /// The number of decimal places in base ten.
446    denom: Denomination,
447}
448
449impl DenominatedAmount {
450    /// Make a new denominated amount representing amount*10^(-denom)
451    pub const fn new(amount: Amount, denom: Denomination) -> Self {
452        Self { amount, denom }
453    }
454
455    /// Return a denominated native token amount.
456    pub const fn native(amount: Amount) -> Self {
457        Self {
458            amount,
459            denom: Denomination(NATIVE_MAX_DECIMAL_PLACES),
460        }
461    }
462
463    /// Check if the inner [`Amount`] is zero.
464    #[inline]
465    pub fn is_zero(&self) -> bool {
466        self.amount.is_zero()
467    }
468
469    /// A precise string representation. The number of
470    /// decimal places in this string gives the denomination.
471    /// This not true of the string produced by the `Display`
472    /// trait.
473    pub fn to_string_precise(&self) -> String {
474        let decimals = self.denom.0 as usize;
475        let mut string = self.amount.raw.to_string();
476        // escape hatch if there are no decimal places
477        if decimals == 0 {
478            return string;
479        }
480        if string.len() > decimals {
481            // Cannot underflow cause `string.len` > `decimals`
482            #[allow(clippy::arithmetic_side_effects)]
483            let idx = string.len() - decimals;
484            string.insert(idx, '.');
485        } else {
486            for _ in string.len()..decimals {
487                string.insert(0, '0');
488            }
489            string.insert(0, '.');
490            string.insert(0, '0');
491        }
492        string
493    }
494
495    /// Find the minimal precision that holds this value losslessly.
496    /// This equates to stripping trailing zeros after the decimal
497    /// place.
498    pub fn canonical(self) -> Self {
499        let mut value = self.amount.raw;
500        let ten = Uint::from(10);
501        let mut denom = self.denom.0;
502        for _ in 0..self.denom.0 {
503            let (div, rem) = value.div_mod(ten);
504            if rem == Uint::zero() {
505                value = div;
506                denom = denom.checked_sub(1).unwrap_or_default();
507            }
508        }
509        Self {
510            amount: Amount { raw: value },
511            denom: denom.into(),
512        }
513    }
514
515    /// Attempt to increase the precision of an amount. Can fail
516    /// if the resulting amount does not fit into 256 bits.
517    pub fn increase_precision(
518        self,
519        denom: Denomination,
520    ) -> Result<Self, AmountParseError> {
521        if denom.0 < self.denom.0 {
522            return Err(AmountParseError::PrecisionDecrease);
523        }
524        // Cannot underflow cause `denom` >= `self.denom`
525        #[allow(clippy::arithmetic_side_effects)]
526        let denom_diff = denom.0 - self.denom.0;
527        Uint::from(10)
528            .checked_pow(Uint::from(denom_diff))
529            .and_then(|scaling| self.amount.raw.checked_mul(scaling))
530            .map(|amount| Self {
531                amount: Amount { raw: amount },
532                denom,
533            })
534            .ok_or(AmountParseError::PrecisionOverflow)
535    }
536
537    /// Create a new [`DenominatedAmount`] with the same underlying
538    /// amout but a new denomination.
539    pub fn redenominate(self, new_denom: u8) -> Self {
540        Self {
541            amount: self.amount,
542            denom: new_denom.into(),
543        }
544    }
545
546    /// Multiply this number by 10^denom and return the computed integer if
547    /// possible. Otherwise error out.
548    pub fn scale(
549        self,
550        denom: impl Into<u8>,
551    ) -> Result<Amount, AmountParseError> {
552        self.increase_precision(Denomination(denom.into()))
553            .map(|x| x.amount)
554    }
555
556    /// Checked multiplication. Returns `None` on overflow.
557    pub fn checked_mul(&self, rhs: DenominatedAmount) -> Option<Self> {
558        let amount = self.amount.checked_mul(rhs.amount)?;
559        let denom = self.denom.0.checked_add(rhs.denom.0)?.into();
560        Some(Self { amount, denom })
561    }
562
563    /// Checked subtraction. Returns `None` on overflow.
564    pub fn checked_sub(&self, mut rhs: DenominatedAmount) -> Option<Self> {
565        let mut lhs = *self;
566        if lhs.denom < rhs.denom {
567            lhs = lhs.increase_precision(rhs.denom).ok()?;
568        } else {
569            rhs = rhs.increase_precision(lhs.denom).ok()?;
570        }
571        let amount = lhs.amount.checked_sub(rhs.amount)?;
572        Some(Self {
573            amount,
574            denom: lhs.denom,
575        })
576    }
577
578    /// Checked addition. Returns `None` on overflow.
579    pub fn checked_add(&self, mut rhs: DenominatedAmount) -> Option<Self> {
580        let mut lhs = *self;
581        if lhs.denom < rhs.denom {
582            lhs = lhs.increase_precision(rhs.denom).ok()?;
583        } else {
584            rhs = rhs.increase_precision(lhs.denom).ok()?;
585        }
586        let amount = lhs.amount.checked_add(rhs.amount)?;
587        Some(Self {
588            amount,
589            denom: lhs.denom,
590        })
591    }
592
593    /// Returns the significand of this number
594    pub const fn amount(&self) -> Amount {
595        self.amount
596    }
597
598    /// Returns the denomination of this number
599    pub const fn denom(&self) -> Denomination {
600        self.denom
601    }
602}
603
604impl Display for DenominatedAmount {
605    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
606        let string = self.to_string_precise();
607        let string = if self.denom.0 > 0 {
608            string.trim_end_matches(['0'])
609        } else {
610            &string
611        };
612        let string = string.trim_end_matches(['.']);
613        f.write_str(string)
614    }
615}
616
617impl FromStr for DenominatedAmount {
618    type Err = AmountParseError;
619
620    fn from_str(s: &str) -> Result<Self, Self::Err> {
621        let precision = s.find('.').map(|pos| {
622            s.len()
623                .checked_sub(pos.checked_add(1).unwrap_or(pos))
624                .unwrap_or_default()
625        });
626        let digits = s
627            .chars()
628            .filter_map(|c| {
629                if c.is_numeric() {
630                    c.to_digit(10).map(Uint::from)
631                } else {
632                    None
633                }
634            })
635            .rev()
636            .collect::<Vec<_>>();
637        if digits.len() != s.len() && precision.is_none()
638            || digits.len() != s.len().checked_sub(1).unwrap_or_default()
639                && precision.is_some()
640        {
641            return Err(AmountParseError::NotNumeric);
642        }
643        if digits.len() > 77 {
644            return Err(AmountParseError::ScaleTooLarge(digits.len(), 77));
645        }
646        let mut value = Uint::default();
647        let ten = Uint::from(10);
648        for (pow, digit) in digits.into_iter().enumerate() {
649            value = ten
650                .checked_pow(Uint::from(pow))
651                .and_then(|scaling| scaling.checked_mul(digit))
652                .and_then(|scaled| value.checked_add(scaled))
653                .ok_or(AmountParseError::InvalidRange)?;
654        }
655        let denom = Denomination(
656            u8::try_from(precision.unwrap_or_default())
657                .map_err(|_e| AmountParseError::PrecisionOverflow)?,
658        );
659        Ok(Self {
660            amount: Amount { raw: value },
661            denom,
662        })
663    }
664}
665
666impl PartialOrd for DenominatedAmount {
667    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
668        Some(self.cmp(other))
669    }
670}
671
672impl Ord for DenominatedAmount {
673    fn cmp(&self, other: &Self) -> Ordering {
674        if self.amount.is_zero() && other.is_zero() {
675            Ordering::Equal
676        } else if self.amount.is_zero() {
677            Ordering::Less
678        } else if other.amount.is_zero() {
679            Ordering::Greater
680        } else if self.denom < other.denom {
681            // Cannot underflow cause `self.denom` < `other.denom`
682            #[allow(clippy::arithmetic_side_effects)]
683            let diff = other.denom.0 - self.denom.0;
684            if diff > 77 {
685                // This branch catches case where exponentiation overflows
686                return Ordering::Greater;
687            }
688            let (div, rem) =
689                other.amount.raw.div_mod(Uint::exp10(diff as usize));
690            let div_ceil = if rem.is_zero() {
691                div
692            } else {
693                div.checked_add(Uint::one()).unwrap_or(Uint::MAX)
694            };
695            let ord = self.amount.raw.cmp(&div_ceil);
696            if let Ordering::Equal = ord {
697                if rem.is_zero() {
698                    Ordering::Equal
699                } else {
700                    Ordering::Greater
701                }
702            } else {
703                ord
704            }
705        } else {
706            // Cannot underflow cause `other.denom` >= `self.denom`
707            #[allow(clippy::arithmetic_side_effects)]
708            let diff = self.denom.0 - other.denom.0;
709            if diff > 77 {
710                // This branch catches case where exponentiation overflows
711                return Ordering::Less;
712            }
713            let (div, rem) =
714                self.amount.raw.div_mod(Uint::exp10(diff as usize));
715            let div_ceil = if rem.is_zero() {
716                div
717            } else {
718                div.checked_add(Uint::one()).unwrap_or(Uint::MAX)
719            };
720            let ord = div_ceil.cmp(&other.amount.raw);
721            if let Ordering::Equal = ord {
722                if rem.is_zero() {
723                    Ordering::Equal
724                } else {
725                    Ordering::Less
726                }
727            } else {
728                ord
729            }
730        }
731    }
732}
733
734impl serde::Serialize for Amount {
735    fn serialize<S>(
736        &self,
737        serializer: S,
738    ) -> std::result::Result<S::Ok, S::Error>
739    where
740        S: serde::Serializer,
741    {
742        let amount_string = self.raw.to_string();
743        serde::Serialize::serialize(&amount_string, serializer)
744    }
745}
746
747impl<'de> serde::Deserialize<'de> for Amount {
748    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
749    where
750        D: serde::Deserializer<'de>,
751    {
752        let amount_string: String =
753            serde::Deserialize::deserialize(deserializer)?;
754        let amt = DenominatedAmount::from_str(&amount_string).unwrap();
755        Ok(amt.amount)
756    }
757}
758
759impl serde::Serialize for DenominatedAmount {
760    fn serialize<S>(
761        &self,
762        serializer: S,
763    ) -> std::result::Result<S::Ok, S::Error>
764    where
765        S: serde::Serializer,
766    {
767        let amount_string = self.to_string_precise();
768        serde::Serialize::serialize(&amount_string, serializer)
769    }
770}
771
772impl<'de> serde::Deserialize<'de> for DenominatedAmount {
773    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
774    where
775        D: serde::Deserializer<'de>,
776    {
777        use serde::de::Error;
778        let amount_string: String =
779            serde::Deserialize::deserialize(deserializer)?;
780        Self::from_str(&amount_string).map_err(D::Error::custom)
781    }
782}
783
784impl From<Amount> for DenominatedAmount {
785    fn from(amount: Amount) -> Self {
786        DenominatedAmount::new(amount, 0.into())
787    }
788}
789
790// Treats the u64 as a value of the raw amount (namnam)
791impl From<u64> for Amount {
792    fn from(val: u64) -> Amount {
793        Amount {
794            raw: Uint::from(val),
795        }
796    }
797}
798
799impl From<Amount> for U256 {
800    fn from(amt: Amount) -> Self {
801        Self(amt.raw.0)
802    }
803}
804
805impl TryFrom<Dec> for Amount {
806    type Error = arith::Error;
807
808    fn try_from(dec: Dec) -> Result<Amount, Self::Error> {
809        // Fails if the dec negative
810        let _ = checked!(Dec(I256::maximum()) - dec)?;
811
812        // Division cannot panic as divisor is non-zero
813        #[allow(clippy::arithmetic_side_effects)]
814        let raw = dec.0.abs() / Uint::exp10(POS_DECIMAL_PRECISION as usize);
815        Ok(Amount { raw })
816    }
817}
818
819impl TryFrom<Amount> for u128 {
820    type Error = std::io::Error;
821
822    fn try_from(value: Amount) -> Result<Self, Self::Error> {
823        let Uint(arr) = value.raw;
824        for word in arr.iter().skip(2) {
825            if *word != 0 {
826                return Err(std::io::Error::new(
827                    std::io::ErrorKind::InvalidInput,
828                    "Integer overflow when casting to u128",
829                ));
830            }
831        }
832        Ok(value.raw.low_u128())
833    }
834}
835
836impl KeySeg for Amount {
837    fn parse(string: String) -> super::storage::Result<Self>
838    where
839        Self: Sized,
840    {
841        let bytes = BASE32HEX_NOPAD.decode(string.as_ref()).map_err(|err| {
842            storage::Error::ParseKeySeg(format!(
843                "Failed parsing {} with {}",
844                string, err
845            ))
846        })?;
847        Ok(Amount {
848            raw: Uint::from_big_endian(&bytes),
849        })
850    }
851
852    fn raw(&self) -> String {
853        let buf = self.raw.to_big_endian();
854        BASE32HEX_NOPAD.encode(&buf)
855    }
856
857    fn to_db_key(&self) -> DbKeySeg {
858        DbKeySeg::StringSeg(self.raw())
859    }
860}
861
862#[allow(missing_docs)]
863#[derive(Error, Debug)]
864pub enum AmountParseError {
865    #[error(
866        "Error decoding token amount, too many decimal places: {0}. Maximum \
867         {1}"
868    )]
869    ScaleTooLarge(usize, u8),
870    #[error(
871        "Error decoding token amount, the value is not within invalid range."
872    )]
873    InvalidRange,
874    #[error("Error converting amount to decimal, number too large.")]
875    ConvertToDecimal,
876    #[error(
877        "Could not convert from string, expected an unsigned 256-bit integer."
878    )]
879    FromString,
880    #[error("Could not parse string as a correctly formatted number.")]
881    NotNumeric,
882    #[error("This amount cannot handle the requested precision in 256 bits.")]
883    PrecisionOverflow,
884    #[error("More precision given in the amount than requested.")]
885    PrecisionDecrease,
886}
887
888impl From<Amount> for Change {
889    fn from(amount: Amount) -> Self {
890        amount.raw.try_into().unwrap()
891    }
892}
893
894impl From<Change> for Amount {
895    fn from(change: Change) -> Self {
896        Amount { raw: change.abs() }
897    }
898}
899
900impl From<Amount> for Uint {
901    fn from(amount: Amount) -> Self {
902        amount.raw
903    }
904}
905
906impl From<Uint> for Amount {
907    fn from(raw: Uint) -> Self {
908        Self { raw }
909    }
910}
911
912/// The four possible u64 words in a [`Uint`].
913/// Used for converting to MASP amounts.
914#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
915#[derive(
916    Copy,
917    Clone,
918    Debug,
919    PartialEq,
920    Eq,
921    PartialOrd,
922    Ord,
923    Hash,
924    BorshSerialize,
925    BorshDeserialize,
926    BorshDeserializer,
927    BorshSchema,
928    Serialize,
929    Deserialize,
930)]
931#[repr(u8)]
932#[allow(missing_docs)]
933#[borsh(use_discriminant = true)]
934pub enum MaspDigitPos {
935    Zero = 0,
936    One,
937    Two,
938    Three,
939}
940
941impl TryFrom<u8> for MaspDigitPos {
942    type Error = &'static str;
943
944    fn try_from(denom: u8) -> Result<Self, Self::Error> {
945        match denom {
946            0 => Ok(Self::Zero),
947            1 => Ok(Self::One),
948            2 => Ok(Self::Two),
949            3 => Ok(Self::Three),
950            _ => Err("Possible MASP denominations must be between 0 and 3"),
951        }
952    }
953}
954
955impl MaspDigitPos {
956    /// Iterator over the possible denominations
957    pub fn iter() -> impl Iterator<Item = MaspDigitPos> {
958        [
959            MaspDigitPos::Zero,
960            MaspDigitPos::One,
961            MaspDigitPos::Two,
962            MaspDigitPos::Three,
963        ]
964        .into_iter()
965    }
966
967    /// Get the corresponding u64 word from the input uint256.
968    pub fn denominate<'a>(&self, amount: impl Into<&'a Amount>) -> u64 {
969        let amount = amount.into();
970        amount.raw.0[*self as usize]
971    }
972}
973
974impl From<Amount> for IbcAmount {
975    fn from(amount: Amount) -> Self {
976        primitive_types::U256(amount.raw.0).into()
977    }
978}
979
980impl TryFrom<IbcAmount> for Amount {
981    type Error = AmountParseError;
982
983    fn try_from(amount: IbcAmount) -> Result<Self, Self::Error> {
984        let uint = Uint(primitive_types::U256::from(amount).0);
985        Self::from_uint(uint, 0)
986    }
987}
988
989impl From<DenominatedAmount> for IbcAmount {
990    fn from(amount: DenominatedAmount) -> Self {
991        amount.amount.into()
992    }
993}
994
995#[allow(missing_docs)]
996#[derive(Error, Debug)]
997pub enum AmountError {
998    #[error("Insufficient amount")]
999    Insufficient,
1000    #[error("Amount overlofow")]
1001    Overflow,
1002}
1003
1004#[cfg(any(test, feature = "testing"))]
1005/// Testing helpers and strategies for tokens
1006#[allow(clippy::arithmetic_side_effects)]
1007pub mod testing {
1008    use proptest::prelude::*;
1009
1010    use super::*;
1011
1012    impl std::ops::Add for Amount {
1013        type Output = Self;
1014
1015        fn add(self, rhs: Self) -> Self::Output {
1016            self.checked_add(rhs).unwrap()
1017        }
1018    }
1019
1020    impl std::ops::AddAssign for Amount {
1021        fn add_assign(&mut self, rhs: Self) {
1022            *self = self.checked_add(rhs).unwrap();
1023        }
1024    }
1025
1026    impl std::ops::Sub for Amount {
1027        type Output = Self;
1028
1029        fn sub(self, rhs: Self) -> Self::Output {
1030            self.checked_sub(rhs).unwrap()
1031        }
1032    }
1033
1034    impl std::ops::SubAssign for Amount {
1035        fn sub_assign(&mut self, rhs: Self) {
1036            *self = *self - rhs;
1037        }
1038    }
1039
1040    impl<T> std::ops::Mul<T> for Amount
1041    where
1042        T: Into<Self>,
1043    {
1044        type Output = Amount;
1045
1046        fn mul(self, rhs: T) -> Self::Output {
1047            self.checked_mul(rhs.into()).unwrap()
1048        }
1049    }
1050
1051    impl std::ops::Mul<Amount> for u64 {
1052        type Output = Amount;
1053
1054        fn mul(self, rhs: Amount) -> Self::Output {
1055            rhs * self
1056        }
1057    }
1058
1059    impl std::ops::Div<u64> for Amount {
1060        type Output = Self;
1061
1062        fn div(self, rhs: u64) -> Self::Output {
1063            Self {
1064                raw: self.raw / Uint::from(rhs),
1065            }
1066        }
1067    }
1068
1069    impl std::iter::Sum for Amount {
1070        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1071            iter.fold(Amount::zero(), |a, b| a + b)
1072        }
1073    }
1074
1075    prop_compose! {
1076        /// Generate an arbitrary denomination
1077        pub fn arb_denomination()(denom in 0u8..) -> Denomination {
1078            Denomination(denom)
1079        }
1080    }
1081
1082    prop_compose! {
1083        /// Generate a denominated amount
1084        pub fn arb_denominated_amount()(
1085            amount in arb_amount(),
1086            denom in arb_denomination(),
1087        ) -> DenominatedAmount {
1088            DenominatedAmount::new(amount, denom)
1089        }
1090    }
1091
1092    /// Generate an arbitrary token amount
1093    pub fn arb_amount() -> impl Strategy<Value = Amount> {
1094        any::<u64>().prop_map(|val| Amount::from_uint(val, 0).unwrap())
1095    }
1096
1097    /// Generate an arbitrary token amount up to and including given `max` value
1098    pub fn arb_amount_ceiled(max: u64) -> impl Strategy<Value = Amount> {
1099        (0..=max).prop_map(|val| Amount::from_uint(val, 0).unwrap())
1100    }
1101
1102    /// Generate an arbitrary non-zero token amount up to and including given
1103    /// `max` value
1104    pub fn arb_amount_non_zero_ceiled(
1105        max: u64,
1106    ) -> impl Strategy<Value = Amount> {
1107        (1..=max).prop_map(|val| Amount::from_uint(val, 0).unwrap())
1108    }
1109}
1110
1111#[cfg(test)]
1112mod tests {
1113    use assert_matches::assert_matches;
1114
1115    use super::*;
1116
1117    #[test]
1118    fn test_token_display() {
1119        let max = Amount::from_uint(u64::MAX, 0).expect("Test failed");
1120        assert_eq!("18446744073709.551615", max.to_string_native());
1121        let max = DenominatedAmount {
1122            amount: max,
1123            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1124        };
1125        assert_eq!("18446744073709.551615", max.to_string());
1126
1127        let whole =
1128            Amount::from_uint(u64::MAX / NATIVE_SCALE * NATIVE_SCALE, 0)
1129                .expect("Test failed");
1130        assert_eq!("18446744073709.000000", whole.to_string_native());
1131        let whole = DenominatedAmount {
1132            amount: whole,
1133            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1134        };
1135        assert_eq!("18446744073709", whole.to_string());
1136
1137        let trailing_zeroes =
1138            Amount::from_uint(123000, 0).expect("Test failed");
1139        assert_eq!("0.123000", trailing_zeroes.to_string_native());
1140        let trailing_zeroes = DenominatedAmount {
1141            amount: trailing_zeroes,
1142            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1143        };
1144        assert_eq!("0.123", trailing_zeroes.to_string());
1145
1146        let zero = Amount::default();
1147        assert_eq!("0.000000", zero.to_string_native());
1148        let zero = DenominatedAmount {
1149            amount: zero,
1150            denom: NATIVE_MAX_DECIMAL_PLACES.into(),
1151        };
1152        assert_eq!("0", zero.to_string());
1153
1154        let amount = DenominatedAmount {
1155            amount: Amount::from_uint(1120, 0).expect("Test failed"),
1156            denom: 3u8.into(),
1157        };
1158        assert_eq!("1.12", amount.to_string());
1159        assert_eq!("1.120", amount.to_string_precise());
1160
1161        let amount = DenominatedAmount {
1162            amount: Amount::from_uint(1120, 0).expect("Test failed"),
1163            denom: 5u8.into(),
1164        };
1165        assert_eq!("0.0112", amount.to_string());
1166        assert_eq!("0.01120", amount.to_string_precise());
1167
1168        let amount = DenominatedAmount {
1169            amount: Amount::from_uint(200, 0).expect("Test failed"),
1170            denom: 0.into(),
1171        };
1172        assert_eq!("200", amount.to_string());
1173        assert_eq!("200", amount.to_string_precise());
1174    }
1175
1176    #[test]
1177    fn test_amount_checked_sub() {
1178        let max = Amount::native_whole(u64::MAX);
1179        let one = Amount::native_whole(1);
1180        let zero = Amount::native_whole(0);
1181
1182        assert_eq!(zero.checked_sub(zero), Some(zero));
1183        assert_eq!(zero.checked_sub(one), None);
1184        assert_eq!(zero.checked_sub(max), None);
1185
1186        assert_eq!(max.checked_sub(zero), Some(max));
1187        assert_eq!(max.checked_sub(one), Some(max - one));
1188        assert_eq!(max.checked_sub(max), Some(zero));
1189    }
1190
1191    #[test]
1192    fn test_serialization_round_trip() {
1193        let amount: Amount = serde_json::from_str(r#""1000000000""#).unwrap();
1194        assert_eq!(
1195            amount,
1196            Amount {
1197                raw: Uint::from(1000000000)
1198            }
1199        );
1200        let serialized = serde_json::to_string(&amount).unwrap();
1201        assert_eq!(serialized, r#""1000000000""#);
1202    }
1203
1204    #[test]
1205    fn test_amount_checked_add() {
1206        let max = Amount::max();
1207        let max_signed = Amount::max_signed();
1208        let one = Amount::native_whole(1);
1209        let zero = Amount::native_whole(0);
1210
1211        assert_eq!(zero.checked_add(zero), Some(zero));
1212        assert_eq!(zero.checked_signed_add(zero), Some(zero));
1213        assert_eq!(zero.checked_add(one), Some(one));
1214        assert_eq!(zero.checked_add(max - one), Some(max - one));
1215        assert_eq!(
1216            zero.checked_signed_add(max_signed - one),
1217            Some(max_signed - one)
1218        );
1219        assert_eq!(zero.checked_add(max), Some(max));
1220        assert_eq!(zero.checked_signed_add(max_signed), Some(max_signed));
1221
1222        assert_eq!(max.checked_add(zero), Some(max));
1223        assert_eq!(max.checked_signed_add(zero), None);
1224        assert_eq!(max.checked_add(one), None);
1225        assert_eq!(max.checked_add(max), None);
1226
1227        assert_eq!(max_signed.checked_add(zero), Some(max_signed));
1228        assert_eq!(max_signed.checked_add(one), Some(max_signed + one));
1229        assert_eq!(max_signed.checked_signed_add(max_signed), None);
1230    }
1231
1232    #[test]
1233    fn test_amount_from_string() {
1234        assert!(Amount::from_str("1.12", 1).is_err());
1235        assert!(Amount::from_str("0.0", 0).is_err());
1236        assert!(Amount::from_str("1.12", 80).is_err());
1237        assert!(Amount::from_str("1.12.1", 3).is_err());
1238        assert!(Amount::from_str("1.1a", 3).is_err());
1239        assert_eq!(
1240            Amount::zero(),
1241            Amount::from_str("0.0", 1).expect("Test failed")
1242        );
1243        assert_eq!(
1244            Amount::zero(),
1245            Amount::from_str(".0", 1).expect("Test failed")
1246        );
1247
1248        let amount = Amount::from_str("1.12", 3).expect("Test failed");
1249        assert_eq!(amount, Amount::from_uint(1120, 0).expect("Test failed"));
1250        let amount = Amount::from_str(".34", 3).expect("Test failed");
1251        assert_eq!(amount, Amount::from_uint(340, 0).expect("Test failed"));
1252        let amount = Amount::from_str("0.34", 3).expect("Test failed");
1253        assert_eq!(amount, Amount::from_uint(340, 0).expect("Test failed"));
1254        let amount = Amount::from_str("34", 1).expect("Test failed");
1255        assert_eq!(amount, Amount::from_uint(340, 0).expect("Test failed"));
1256    }
1257
1258    #[test]
1259    fn test_from_masp_denominated() {
1260        let uint = Uint([15u64, 16, 17, 18]);
1261        let original = Amount::from_uint(uint, 0).expect("Test failed");
1262        for denom in MaspDigitPos::iter() {
1263            let word = denom.denominate(&original);
1264            assert_eq!(word, denom as u64 + 15u64);
1265            let amount = Amount::from_masp_denominated(word, denom);
1266            let raw = Uint::from(amount).0;
1267            let mut expected = [0u64; 4];
1268            expected[denom as usize] = word;
1269            assert_eq!(raw, expected);
1270        }
1271    }
1272
1273    #[test]
1274    fn test_key_seg() {
1275        let original = Amount::from_uint(1234560000, 0).expect("Test failed");
1276        let key = original.raw();
1277        let amount = Amount::parse(key).expect("Test failed");
1278        assert_eq!(amount, original);
1279    }
1280
1281    #[test]
1282    fn test_amount_is_zero() {
1283        let zero = Amount::zero();
1284        assert!(zero.is_zero());
1285
1286        let non_zero = Amount::from_uint(1, 0).expect("Test failed");
1287        assert!(!non_zero.is_zero());
1288    }
1289
1290    #[test]
1291    fn test_token_amount_mul_ceil() {
1292        let one = Amount::from(1);
1293        let two = Amount::from(2);
1294        let three = Amount::from(3);
1295        let dec = Dec::from_str("0.34").unwrap();
1296        assert_eq!(one.mul_ceil(dec).unwrap(), one);
1297        assert_eq!(two.mul_ceil(dec).unwrap(), one);
1298        assert_eq!(three.mul_ceil(dec).unwrap(), two);
1299
1300        assert_matches!(one.mul_ceil(-dec), Err(_));
1301        assert_matches!(one.mul_ceil(-Dec::new(1, 12).unwrap()), Err(_));
1302        assert_matches!(
1303            Amount::native_whole(1).mul_ceil(-Dec::new(1, 12).unwrap()),
1304            Err(_)
1305        );
1306    }
1307
1308    #[test]
1309    fn test_token_amount_mul_floor() {
1310        let zero = Amount::zero();
1311        let one = Amount::from(1);
1312        let two = Amount::from(2);
1313        let three = Amount::from(3);
1314        let dec = Dec::from_str("0.34").unwrap();
1315        assert_eq!(one.mul_floor(dec).unwrap(), zero);
1316        assert_eq!(two.mul_floor(dec).unwrap(), zero);
1317        assert_eq!(three.mul_floor(dec).unwrap(), one);
1318
1319        assert_matches!(one.mul_floor(-dec), Err(_));
1320        assert_matches!(one.mul_floor(-Dec::new(1, 12).unwrap()), Err(_));
1321        assert_matches!(
1322            Amount::native_whole(1).mul_floor(-Dec::new(1, 12).unwrap()),
1323            Err(_)
1324        );
1325    }
1326
1327    #[test]
1328    fn test_denominateed_arithmetic() {
1329        let a = DenominatedAmount::new(10.into(), 3.into());
1330        let b = DenominatedAmount::new(10.into(), 2.into());
1331        let c = DenominatedAmount::new(110.into(), 3.into());
1332        let d = DenominatedAmount::new(90.into(), 3.into());
1333        let e = DenominatedAmount::new(100.into(), 5.into());
1334        let f = DenominatedAmount::new(100.into(), 3.into());
1335        let g = DenominatedAmount::new(0.into(), 3.into());
1336        assert_eq!(a.checked_add(b).unwrap(), c);
1337        assert_eq!(b.checked_sub(a).unwrap(), d);
1338        assert_eq!(a.checked_mul(b).unwrap(), e);
1339        assert!(a.checked_sub(b).is_none());
1340        assert_eq!(c.checked_sub(a).unwrap(), f);
1341        assert_eq!(c.checked_sub(c).unwrap(), g);
1342    }
1343
1344    #[test]
1345    fn test_denominated_amt_ord() {
1346        let denom_1 = DenominatedAmount {
1347            amount: Amount::from_uint(15, 0).expect("Test failed"),
1348            denom: 1.into(),
1349        };
1350        let denom_2 = DenominatedAmount {
1351            amount: Amount::from_uint(1500, 0).expect("Test failed"),
1352            denom: 3.into(),
1353        };
1354        // The psychedelic case. Partial ordering works on the underlying
1355        // amounts but `Eq` also checks the equality of denoms.
1356        assert_eq!(
1357            denom_1.partial_cmp(&denom_2).expect("Test failed"),
1358            Ordering::Equal
1359        );
1360        assert_eq!(
1361            denom_2.partial_cmp(&denom_1).expect("Test failed"),
1362            Ordering::Equal
1363        );
1364        assert_ne!(denom_1, denom_2);
1365
1366        let denom_1 = DenominatedAmount {
1367            amount: Amount::from_uint(15, 0).expect("Test failed"),
1368            denom: 1.into(),
1369        };
1370        let denom_2 = DenominatedAmount {
1371            amount: Amount::from_uint(1501, 0).expect("Test failed"),
1372            denom: 3.into(),
1373        };
1374        assert_eq!(
1375            denom_1.partial_cmp(&denom_2).expect("Test failed"),
1376            Ordering::Less
1377        );
1378        assert_eq!(
1379            denom_2.partial_cmp(&denom_1).expect("Test failed"),
1380            Ordering::Greater
1381        );
1382        let denom_1 = DenominatedAmount {
1383            amount: Amount::from_uint(15, 0).expect("Test failed"),
1384            denom: 1.into(),
1385        };
1386        let denom_2 = DenominatedAmount {
1387            amount: Amount::from_uint(1499, 0).expect("Test failed"),
1388            denom: 3.into(),
1389        };
1390        assert_eq!(
1391            denom_1.partial_cmp(&denom_2).expect("Test failed"),
1392            Ordering::Greater
1393        );
1394        assert_eq!(
1395            denom_2.partial_cmp(&denom_1).expect("Test failed"),
1396            Ordering::Less
1397        );
1398    }
1399
1400    #[test]
1401    fn test_token_amount_from_u128() {
1402        for val in [
1403            u128::MIN,
1404            u128::MIN + 1,
1405            u128::from(u64::MAX) - 1,
1406            u128::from(u64::MAX),
1407            u128::from(u64::MAX) + 1,
1408            u128::MAX - 1,
1409            u128::MAX,
1410        ] {
1411            let raw = Uint::from(val);
1412            let amount = Amount::from_u128(val);
1413            assert_eq!(raw, amount.raw);
1414            assert_eq!(amount.raw.as_u128(), val);
1415        }
1416    }
1417}