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
use std::sync::Arc;

use alloy_primitives::{Address, Bytes};
use alloy_sol_types::SolCall;
use brontes_core::missing_token_info::load_missing_token_info;
use brontes_types::{
    db::traits::{DBWriter, LibmdbxReader},
    normalized_actions::NormalizedTransfer,
    traits::TracingProvider,
    ToScaledRational,
};
use malachite::{num::basic::traits::Zero, Rational};
use reth_primitives::U256;

alloy_sol_macro::sol!(
    function transfer(address, uint) returns(bool);
    function transferFrom(address, address, uint) returns(bool);
    function withdraw(uint wad);
    function deposit();
);

pub async fn try_decode_transfer<T: TracingProvider, DB: LibmdbxReader + DBWriter>(
    idx: u64,
    calldata: Bytes,
    from: Address,
    token: Address,
    db: &DB,
    provider: &Arc<T>,
    block: u64,
    value: U256,
) -> eyre::Result<NormalizedTransfer> {
    let (from_addr, to_addr, amount) = if let Some((from_addr, to_addr, amount)) =
        transferCall::abi_decode(&calldata, false)
            .map(|t| Some((from, t._0, t._1)))
            .unwrap_or_else(|_| {
                transferFromCall::abi_decode(&calldata, false)
                    .ok()
                    .map(|t| (t._0, t._1, t._2))
            }) {
        (from_addr, to_addr, amount)
    } else if let Ok(amount) = withdrawCall::abi_decode(&calldata, false) {
        (from, Address::ZERO, amount.wad)
    } else if depositCall::abi_decode(&calldata, false).is_ok() {
        (token, from, value)
    } else {
        return Err(eyre::eyre!("failed to decode transfer for token: {:?}", token))
    };

    if db.try_fetch_token_info(token).is_err() {
        load_missing_token_info(provider, db, block, token).await
    }

    let token_info = db.try_fetch_token_info(token)?;

    Ok(NormalizedTransfer {
        amount:      amount.to_scaled_rational(token_info.decimals),
        token:       token_info,
        to:          to_addr,
        from:        from_addr,
        trace_index: idx,
        msg_value:   value,
        fee:         Rational::ZERO,
    })
}