1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
pub mod types;

use ethers::{
    prelude::signer::SignerMiddlewareError,
    providers::{JsonRpcClient, Middleware, PendingTransaction},
    signers::Signer,
};
use tracing::{error, info};

use crate::types::{TxErrors, TxStatus};

/// Handles the transaction and returns a TxStatus
pub async fn handle_tx<P: JsonRpcClient, S: Signer>(
    tx: Result<PendingTransaction<'_, P>, SignerMiddlewareError<impl Middleware, S>>,
) -> TxStatus {
    let tx = tx.map_err(|e| format!("Failed to send transaction: {:?}", e));

    let tx = match tx {
        Ok(tx) => tx,
        Err(e) => {
            error!("Failed to send transaction: {:?}", e);
            return TxStatus::Failed(TxErrors::Failed(e));
        }
    };

    let hash = tx.tx_hash();

    info!("Mining tx hash: {:?}", hash);
    let receipt = tx
        .await
        .map_err(|e| format!("Failed to mine transaction: {:?}", e));
    let receipt = match receipt {
        Ok(receipt) => receipt,
        Err(e) => return TxStatus::Failed(TxErrors::Failed(e)),
    };
    match receipt {
        Some(receipt) => {
            info!("Tx mined!");
            if receipt.status == Some(0.into()) {
                info!("Tx reverted!");
                return types::TxStatus::Failed(TxErrors::Reverted(receipt));
            }
            TxStatus::Successful(receipt)
        }
        None => {
            error!("No receipt for tx hash: {:?}", hash);
            // I don't even think this is possible
            TxStatus::Failed(TxErrors::NoReceipt(hash))
        }
    }
}

#[cfg(test)]
mod tests {
    use ethers::{
        prelude::SignerMiddleware,
        signers::{LocalWallet, Signer},
        types::TransactionRequest,
        utils::{parse_ether, Anvil},
    };

    use crate::handle_tx;

    #[tokio::test]
    async fn it_works() {
        use ethers::providers::{Http, Middleware, Provider};
        use std::sync::Arc;

        let anvil = Anvil::new().spawn();
        let signer: LocalWallet = anvil.keys()[0].clone().into();
        let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();

        let client = SignerMiddleware::new(provider.clone(), signer.with_chain_id(31337u64));
        let client = Arc::new(client);

        let tx = TransactionRequest::pay(anvil.addresses()[0], 100);

        let tx = client.send_transaction(tx, None).await;
        let status = handle_tx(tx).await;
        println!("{:?}", status);

        let tx_2 = TransactionRequest::pay(anvil.addresses()[1], parse_ether("10000000").unwrap());
        let tx = client.send_transaction(tx_2, None).await;

        let status = handle_tx(tx).await;
        println!("{:?}", status);
    }
}