debot_ether_ether_utils/token/
token.rs1use 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}