1pub mod types;
2
3use std::error::Error;
4
5use ethers::providers::{JsonRpcClient, PendingTransaction};
6use tracing::{error, info};
7
8use crate::types::{TxErrors, TxStatus};
9
10pub async fn handle_tx<P: JsonRpcClient, E: Error>(
12 tx: Result<PendingTransaction<'_, P>, E>,
13) -> TxStatus {
14 let tx = tx.map_err(|e| format!("Failed to send transaction: {:?}", e));
15
16 let tx = match tx {
17 Ok(tx) => tx,
18 Err(e) => {
19 error!("Failed to send transaction: {:?}", e);
20 return TxStatus::Failed(TxErrors::Failed(e));
21 }
22 };
23
24 let hash = tx.tx_hash();
25
26 info!("Mining tx hash: {:?}", hash);
27 let receipt = tx
28 .await
29 .map_err(|e| format!("Failed to mine transaction: {:?}", e));
30 let receipt = match receipt {
31 Ok(receipt) => receipt,
32 Err(e) => return TxStatus::Failed(TxErrors::Failed(e)),
33 };
34 match receipt {
35 Some(receipt) => {
36 info!("Tx mined!");
37 if receipt.status == Some(0.into()) {
38 info!("Tx reverted!");
39 return types::TxStatus::Failed(TxErrors::Reverted(receipt));
40 }
41 TxStatus::Successful(receipt)
42 }
43 None => {
44 error!("No receipt for tx hash: {:?}", hash);
45 TxStatus::Failed(TxErrors::NoReceipt(hash))
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use ethers::{
54 prelude::SignerMiddleware,
55 signers::{LocalWallet, Signer},
56 types::TransactionRequest,
57 utils::{parse_ether, Anvil},
58 };
59
60 use crate::handle_tx;
61
62 #[tokio::test]
63 async fn it_works() {
64 use ethers::providers::{Http, Middleware, Provider};
65 use std::sync::Arc;
66
67 let anvil = Anvil::new().spawn();
68 let signer: LocalWallet = anvil.keys()[0].clone().into();
69 let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
70
71 let client = SignerMiddleware::new(provider.clone(), signer.with_chain_id(31337u64));
72 let client = Arc::new(client);
73
74 let tx = TransactionRequest::pay(anvil.addresses()[0], 100);
75
76 let tx = client.send_transaction(tx, None).await;
77 let status = handle_tx(tx).await;
78 println!("{:?}", status);
79
80 let tx_2 = TransactionRequest::pay(anvil.addresses()[1], parse_ether("10000000").unwrap());
81 let tx = client.send_transaction(tx_2, None).await;
82
83 let status = handle_tx(tx).await;
84 println!("{:?}", status);
85 }
86}