1use std::fmt::Display;
2use std::str::FromStr;
3
4pub use ethers_eip2718::*;
5pub use ethers_macros::*;
6pub use ethers_primitives::*;
7pub use ethers_provider::*;
8pub use ethers_signer::signer::Signer;
9pub use serde::{Deserialize, Serialize};
10pub use serde_ethabi::from_abi;
11pub use serde_ethabi::to_abi;
12
13pub use anyhow::Error;
14use serde_json::json;
15
16#[derive(Debug, thiserror::Error)]
18pub enum ClientError {
19 #[error("TxFailure: {0}")]
21 TxFailure(H256),
22
23 #[error("DeployContract: contract_address field of receipt is null,{0}")]
25 DeployContract(H256),
26 #[error("SignerExpect: method {0} expect signer")]
28 SignerExpect(String),
29 #[error("Accounts: signer return empty accounts list")]
31 Accounts,
32}
33
34#[derive(Clone, Debug, Serialize, Deserialize, Default)]
35pub struct TxOptions {
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub gas_price: Option<U256>,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub value: Option<U256>,
42}
43
44impl<'a> TryFrom<&'a str> for TxOptions {
45 type Error = anyhow::Error;
46 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
47 Ok(serde_json::from_str(value)?)
48 }
49}
50
51impl TryFrom<String> for TxOptions {
52 type Error = anyhow::Error;
53 fn try_from(value: String) -> Result<Self, Self::Error> {
54 Ok(serde_json::from_str(&value)?)
55 }
56}
57
58impl TryFrom<serde_json::Value> for TxOptions {
59 type Error = anyhow::Error;
60 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
61 Ok(serde_json::from_value(value)?)
62 }
63}
64
65pub trait ToTxOptions {
66 fn to_tx_options(self) -> TxOptions;
67}
68
69impl<T: EthereumUnit> ToTxOptions for T {
70 fn to_tx_options(self) -> TxOptions {
71 TxOptions {
72 gas_price: None,
73 value: Some(self.to_u256()),
74 }
75 }
76}
77
78#[derive(Clone)]
80pub struct Client {
81 pub provider: Provider,
83 pub signer: Option<Signer>,
85}
86
87impl From<(Provider, Signer)> for Client {
88 fn from((provider, signer): (Provider, Signer)) -> Self {
89 Self {
90 provider,
91 signer: Some(signer),
92 }
93 }
94}
95
96impl Client {
97 pub async fn deploy_contract(
98 &self,
99 constract_name: &str,
100 mut call_data: Vec<u8>,
101 deploy_data: &str,
102 ops: TxOptions,
103 ) -> anyhow::Result<Address> {
104 let mut buff = Vec::<u8>::from_eth_hex(deploy_data)?;
105
106 buff.append(&mut call_data);
107
108 let tx_hash = self
109 ._send_raw_transaction(constract_name, None, buff, ops, false)
110 .await?;
111
112 let receipt = self
113 .provider
114 .register_transaction_listener(tx_hash.clone())?
115 .wait()
116 .await?;
117
118 let status = receipt
119 .status
120 .ok_or(ClientError::TxFailure(tx_hash.clone()))?;
121
122 match status {
123 Status::Success => {
124 if let Some(contract_address) = receipt.contract_address {
125 return Ok(contract_address);
126 } else {
127 return Err(ClientError::TxFailure(tx_hash).into());
128 }
129 }
130 Status::Failure => return Err(ClientError::TxFailure(tx_hash).into()),
131 }
132 }
133
134 pub async fn eth_call(
136 &self,
137 method_name: &str,
138 to: &Address,
139 mut call_data: Vec<u8>,
140 ) -> anyhow::Result<Vec<u8>> {
141 log::debug!("eth_call {}", method_name);
142
143 let mut provider = self.provider.clone();
144
145 let mut selector_name = keccak256(method_name.as_bytes())[0..4].to_vec();
146
147 selector_name.append(&mut call_data);
148
149 let call_data: Bytes = selector_name.into();
150
151 let tx: LegacyTransactionRequest = json!({
152 "to": to,
153 "data":call_data,
154 })
155 .try_into()?;
156
157 let result = provider.eth_call(tx, None::<BlockNumberOrTag>).await?;
158
159 Ok(result.0)
160 }
161
162 pub async fn send_raw_transaction(
169 &self,
170 method_name: &str,
171 to: &Address,
172 call_data: Vec<u8>,
173 ops: TxOptions,
174 ) -> anyhow::Result<DefaultTransactionReceipter> {
175 let tx_hash = self
176 ._send_raw_transaction(method_name, Some(to), call_data, ops, true)
177 .await?;
178
179 self.provider.register_transaction_listener(tx_hash.clone())
180 }
181
182 async fn _send_raw_transaction(
183 &self,
184 method_name: &str,
185 to: Option<&Address>,
186 mut call_data: Vec<u8>,
187 ops: TxOptions,
188 selector: bool,
189 ) -> anyhow::Result<H256> {
190 let mut provider = self.provider.clone();
191
192 let mut signer = self
193 .signer
194 .clone()
195 .ok_or(ClientError::SignerExpect(method_name.to_owned()))?;
196
197 let address = {
198 let mut accounts = signer.accounts().await?;
199
200 if accounts.is_empty() {
201 return Err(ClientError::Accounts.into());
202 }
203
204 accounts.remove(0)
205 };
206
207 let nonce = provider.eth_get_transaction_count(address).await?;
209
210 log::debug!(
211 target: method_name,
212 "Fetch account {} nonce, {}",
213 address.to_checksum_string(),
214 nonce
215 );
216
217 let chain_id = provider.eth_chain_id().await?;
219
220 log::debug!(target: method_name, "Fetch chain_id, {}", chain_id);
221
222 let call_data = if selector {
223 let mut selector_name = keccak256(method_name.as_bytes())[0..4].to_vec();
224
225 selector_name.append(&mut call_data);
226
227 selector_name
228 } else {
229 call_data
230 };
231
232 let mut tx = LegacyTransactionRequest {
233 chain_id: Some(chain_id),
234 nonce: Some(nonce),
235 to: to.map(|c| c.clone()),
236 data: Some(call_data.into()),
237 value: ops.value,
238 ..Default::default()
239 };
240
241 let gas = provider
243 .eth_estimate_gas(tx.clone(), None::<BlockNumberOrTag>)
244 .await?;
245
246 log::debug!(target: method_name, "Fetch estimate gas, {}", gas);
247
248 tx.gas = Some(gas);
249
250 let gas_price = if let Some(gas_price) = ops.gas_price {
253 gas_price
254 } else {
255 provider.eth_gas_price().await?
256 };
257
258 log::debug!(target: method_name, "Fetch gas price, {}", gas_price);
259
260 tx.gas_price = Some(gas_price);
261
262 log::debug!(
263 target: method_name,
264 "Try sign transaction, {}",
265 serde_json::to_string(&tx)?,
266 );
267
268 let signed_tx = signer.sign_eth_transaction(tx).await?;
269
270 log::debug!(
271 target: method_name,
272 "Signed transaction, {}",
273 signed_tx.to_string()
274 );
275
276 let hash = provider.eth_send_raw_transaction(signed_tx).await?;
277
278 log::debug!(target: method_name, "Send transaction success, {}", hash);
279
280 Ok(hash)
281 }
282
283 pub async fn balance(&self) -> anyhow::Result<U256> {
287 let mut signer = self
288 .signer
289 .clone()
290 .ok_or(ClientError::SignerExpect("balance".to_owned()))?;
291
292 let address = signer.address().await?;
293
294 Ok(self.provider.clone().eth_get_balance(address).await?)
295 }
296}
297
298#[derive(Debug)]
299pub struct AbiEvent(pub ethbind::json::Event);
300
301impl FromStr for AbiEvent {
302 type Err = serde_json::Error;
303 fn from_str(s: &str) -> Result<Self, Self::Err> {
304 serde_json::from_str(s).map(|v| Self(v))
305 }
306}
307
308impl Display for AbiEvent {
309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
310 write!(f, "{}", serde_json::to_string(&self.0).unwrap())
311 }
312}