ethers_tx_handler/
lib.rs

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
10/// Handles the transaction and returns a TxStatus
11pub 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            // I don't even think this is possible
46            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}