debot_ether_ether_utils/token/
token.rs

1// token.rs
2
3use ethers::types::U256;
4use ethers::{
5    abi::Abi, contract::Contract, middleware::SignerMiddleware, providers::Http,
6    providers::Provider, signers::LocalWallet, types::Address,
7};
8use ethers_middleware::NonceManagerMiddleware;
9
10use std::error::Error;
11use std::sync::Arc;
12static ERC20_TOKEN_ABI_JSON: &'static [u8] = include_bytes!("../../resources/ERC20TokenABI.json");
13
14#[derive(Clone)]
15pub enum BlockChain {
16    BscChain { chain_id: u64 },
17    PolygonChain { chain_id: u64 },
18    BaseChain { chain_id: u64 },
19}
20
21#[derive(Clone)]
22pub struct AnchorToken {
23    block_chain: BlockChain,
24    provider: Arc<NonceManagerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>>>,
25    address: Address,
26    symbol_name: String,
27    decimals: Option<u8>,
28    abi: Abi,
29    token_contract:
30        Option<Contract<NonceManagerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>>>>,
31}
32
33impl AnchorToken {
34    pub fn new(
35        block_chain: BlockChain,
36        provider: Arc<NonceManagerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>>>,
37        address: Address,
38        symbol_name: String,
39        decimals: Option<u8>,
40    ) -> Self {
41        let abi = Abi::load(ERC20_TOKEN_ABI_JSON).unwrap();
42        Self {
43            block_chain,
44            provider,
45            address,
46            symbol_name,
47            decimals,
48            abi,
49            token_contract: None,
50        }
51    }
52
53    pub async fn create_token_contract(
54        &mut self,
55    ) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
56        if self.token_contract.is_none() {
57            let token_contract =
58                Contract::new(self.address, self.abi.clone(), self.provider.clone());
59            self.token_contract = Some(token_contract);
60        }
61        Ok(())
62    }
63
64    pub fn block_chain_id(&self) -> u64 {
65        match &self.block_chain {
66            BlockChain::BscChain { chain_id } => *chain_id,
67            BlockChain::PolygonChain { chain_id } => *chain_id,
68            BlockChain::BaseChain { chain_id } => *chain_id,
69        }
70    }
71
72    pub fn address(&self) -> Address {
73        self.address
74    }
75
76    pub fn symbol_name(&self) -> &str {
77        &self.symbol_name
78    }
79
80    pub fn decimals(&self) -> Option<u8> {
81        self.decimals
82    }
83
84    pub async fn initialize(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
85        self.create_token_contract().await?;
86
87        let decimals: u8 = self
88            .token_contract()?
89            .method("decimals", ())?
90            .call()
91            .await
92            .map_err(|e| {
93                Box::new(std::io::Error::new(
94                    std::io::ErrorKind::Other,
95                    format!(
96                        "Failed to call 'decimals' method for {}: {}",
97                        self.symbol_name(),
98                        e
99                    ),
100                )) as Box<dyn Error + Send + Sync>
101            })?;
102
103        self.decimals = Some(decimals);
104
105        Ok(())
106    }
107
108    pub fn token_contract(
109        &self,
110    ) -> Result<
111        &Contract<NonceManagerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>>>,
112        Box<dyn Error + Send + Sync>,
113    > {
114        match &self.token_contract {
115            Some(contract) => Ok(contract),
116            None => Err(Box::new(std::io::Error::new(
117                std::io::ErrorKind::Other,
118                "Token contract not created",
119            ))),
120        }
121    }
122
123    pub async fn approve(
124        &self,
125        spender: Address,
126        amount: U256,
127    ) -> Result<(), Box<dyn Error + Send + Sync>> {
128        let contract = self.token_contract()?;
129        let call = contract.method::<_, ()>("approve", (spender, amount))?;
130        call.send().await?;
131        Ok(())
132    }
133
134    pub async fn allowance(
135        &self,
136        owner: Address,
137        spender: Address,
138    ) -> Result<U256, Box<dyn Error + Send + Sync>> {
139        let contract = self.token_contract()?;
140        let allowance: U256 = contract
141            .method("allowance", (owner, spender))?
142            .call()
143            .await?;
144        Ok(allowance)
145    }
146
147    pub async fn balance_of(&self, owner: Address) -> Result<U256, Box<dyn Error + Send + Sync>> {
148        let contract = self.token_contract()?;
149        let balance: U256 = contract.method("balanceOf", owner)?.call().await?;
150        Ok(balance)
151    }
152
153    pub async fn transfer(
154        &self,
155        recipient: Address,
156        amount: U256,
157    ) -> Result<(), Box<dyn Error + Send + Sync>> {
158        let contract = self.token_contract()?;
159        let call = contract.method::<_, ()>("transfer", (recipient, amount))?;
160        call.send().await?;
161        Ok(())
162    }
163}
164
165#[async_trait::async_trait]
166pub trait Token: Send + Sync {
167    fn new(
168        block_chain: BlockChain,
169        provider: Arc<NonceManagerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>>>,
170        address: Address,
171        symbol_name: String,
172        decimals: Option<u8>,
173    ) -> Self
174    where
175        Self: Sized;
176    fn clone_box(&self) -> Box<dyn Token>;
177    async fn initialize(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
178    fn block_chain(&self) -> BlockChain;
179    fn block_chain_id(&self) -> u64;
180    fn address(&self) -> Address;
181    fn symbol_name(&self) -> &str;
182    fn decimals(&self) -> Option<u8>;
183    async fn approve(
184        &self,
185        spender: Address,
186        amount: U256,
187    ) -> Result<(), Box<dyn Error + Send + Sync>>;
188    async fn allowance(
189        &self,
190        owner: Address,
191        spender: Address,
192    ) -> Result<U256, Box<dyn Error + Send + Sync>>;
193    async fn balance_of(&self, owner: Address) -> Result<U256, Box<dyn Error + Send + Sync>>;
194    async fn transfer(
195        &self,
196        recipient: Address,
197        amount: U256,
198    ) -> Result<(), Box<dyn Error + Send + Sync>>;
199}
200
201impl Clone for Box<dyn Token> {
202    fn clone(&self) -> Box<dyn Token> {
203        self.clone_box()
204    }
205}