1use alloy::{
4 primitives::{Address, U256},
5 providers::DynProvider,
6};
7
8use crate::{Result, token::erc20::ERC20};
9
10pub mod erc20;
11pub mod identity;
12
13pub use identity::TokenIdentifier;
14
15#[derive(Debug, Clone, PartialEq)]
17pub struct Token {
18 pub identifier: TokenIdentifier,
20 pub name: String,
22 pub symbol: String,
24 pub decimals: u8,
26}
27
28const FIAT_DECIMALS: u8 = 6;
29
30impl Token {
31 pub async fn new(identifier: TokenIdentifier, provider: &DynProvider) -> Result<Self> {
35 let (name, symbol, decimals) = match &identifier {
36 TokenIdentifier::ERC20 { address } => {
37 let erc20 = ERC20::new(*address, provider);
38
39 (
40 erc20.name().call().await?,
41 erc20.symbol().call().await?,
42 erc20.decimals().call().await?,
43 )
44 }
45 TokenIdentifier::Fiat { symbol } => (symbol.clone(), symbol.clone(), FIAT_DECIMALS),
46 TokenIdentifier::Native => ("Native".to_string(), "ETH".to_string(), 18),
47 };
48
49 Ok(Self {
50 identifier,
51 name,
52 symbol,
53 decimals,
54 })
55 }
56
57 pub async fn nominal_amount(&self) -> U256 {
59 U256::from(10).pow(U256::from(self.decimals))
60 }
61
62 pub fn format_amount(&self, amount: U256, precision: usize) -> crate::Result<String> {
64 let amount = amount
65 .to_string()
66 .parse::<f64>()
67 .map_err(|e| crate::error::EthPricesError::InvalidTokenAmount(e.to_string()))?;
68 let amount = amount / 10_f64.powf(self.decimals as f64);
69 Ok(format!("{:.precision$}", amount))
70 }
71
72 pub fn address(&self) -> Option<Address> {
76 match &self.identifier {
77 TokenIdentifier::ERC20 { address } => Some(*address),
78 TokenIdentifier::Fiat { .. } => None,
79 TokenIdentifier::Native => None,
80 }
81 }
82}