near_api/types/
tokens.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use near_token::NearToken;
use serde::{Deserialize, Serialize};

use crate::errors::DecimalNumberParsingError;

pub const USDT_BALANCE: FTBalance = FTBalance::with_decimals_and_symbol(6, "USDC");
pub const USDC_BALANCE: FTBalance = FTBalance::with_decimals_and_symbol(6, "USDT");
pub const W_NEAR_BALANCE: FTBalance = FTBalance::with_decimals_and_symbol(24, "wNEAR");

#[derive(Debug, Clone, PartialEq, Default, Eq, Serialize, Deserialize)]
pub struct FTBalance {
    balance: u128,
    decimals: u8,
    symbol: &'static str,
}

impl FTBalance {
    pub const fn with_decimals(decimals: u8) -> Self {
        Self {
            balance: 0,
            decimals,
            symbol: "FT",
        }
    }

    pub const fn with_decimals_and_symbol(decimals: u8, symbol: &'static str) -> Self {
        Self {
            balance: 0,
            decimals,
            symbol,
        }
    }

    pub const fn with_amount(&self, amount: u128) -> Self {
        Self {
            balance: amount,
            decimals: self.decimals,
            symbol: self.symbol,
        }
    }

    pub const fn with_whole_amount(&self, amount: u128) -> Self {
        Self {
            balance: amount * 10u128.pow(self.decimals as u32),
            decimals: self.decimals,
            symbol: self.symbol,
        }
    }

    pub fn with_float_str(&self, float_str: &str) -> Result<Self, DecimalNumberParsingError> {
        crate::common::utils::parse_decimal_number(float_str, 10u128.pow(self.decimals as u32))
            .map(|amount| self.with_amount(amount))
    }

    pub const fn amount(&self) -> u128 {
        self.balance
    }

    pub const fn to_whole(&self) -> u128 {
        self.balance / 10u128.pow(self.decimals as u32)
    }

    pub const fn decimals(&self) -> u8 {
        self.decimals
    }
}

impl std::fmt::Display for FTBalance {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let whole_part = self.to_whole();
        let fractional_part = self.balance % 10u128.pow(self.decimals as u32);

        let fractional_part_str = format!(
            "{:0width$}",
            fractional_part,
            width = self.decimals as usize
        );
        let fractional_part_str = fractional_part_str.trim_end_matches('0');

        if fractional_part_str.is_empty() {
            return write!(f, "{} {}", whole_part, self.symbol);
        }

        write!(f, "{}.{} {}", whole_part, fractional_part_str, self.symbol)
    }
}

#[derive(Debug, Clone, PartialEq, Default, Eq, Serialize, Deserialize)]
pub struct UserBalance {
    pub liquid: NearToken,
    pub locked: NearToken,
    pub storage_usage: u64,
}

#[cfg(test)]
mod tests {
    use super::FTBalance;

    #[test]
    fn ft_balance_default() {
        assert_eq!(
            FTBalance::with_decimals(5).with_whole_amount(5).amount(),
            500000
        );
        assert_eq!(FTBalance::with_decimals(5).with_amount(5).amount(), 5);

        assert_eq!(
            FTBalance::with_decimals(5).with_whole_amount(5).to_whole(),
            5
        );
    }

    #[test]
    fn ft_balance_str() {
        assert_eq!(
            FTBalance::with_decimals(5)
                .with_float_str("5")
                .unwrap()
                .amount(),
            500000
        );
        assert_eq!(
            FTBalance::with_decimals(5)
                .with_float_str("5.00001")
                .unwrap()
                .amount(),
            500001
        );
        assert_eq!(
            FTBalance::with_decimals(5)
                .with_float_str("5.55")
                .unwrap()
                .amount(),
            555000
        );
    }
}