use alloy::{
primitives::{address, utils::format_units, Address, TxKind, U256},
sol,
sol_types::SolCall,
};
use anyhow::Result;
use revm_trace::{
types::SlotAccessType, utils::erc20_utils::get_token_infos, SimulationBatch, SimulationTx,
TransactionTrace, TxInspector,
};
#[cfg(not(feature = "foundry-fork"))]
use revm_trace::create_evm_with_tracer;
#[cfg(feature = "foundry-fork")]
use revm_trace::create_shared_evm_with_tracer;
sol!(
contract ERC20 {
function transfer(address to, uint256 amount) external returns (bool);
}
);
fn encode_erc20_transfer(to: Address, amount: U256) -> Vec<u8> {
ERC20::transferCall { to, amount }.abi_encode()
}
const ETH_RPC_URL: &str = "https://eth.llamarpc.com";
#[tokio::main]
async fn main() -> Result<()> {
#[cfg(not(feature = "foundry-fork"))]
println!("Using AlloyDB backend for EVM simulation");
#[cfg(feature = "foundry-fork")]
println!("Using Foundry fork backend for EVM simulation");
let inspector = TxInspector::new();
#[cfg(not(feature = "foundry-fork"))]
let mut evm = create_evm_with_tracer(ETH_RPC_URL, inspector).await?;
#[cfg(feature = "foundry-fork")]
let mut evm = create_shared_evm_with_tracer(ETH_RPC_URL, inspector).await?;
let usdc = address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
let transfer_data = encode_erc20_transfer(
address!("34e5dacdc16ff5bcdbdfa66c21a20f46347d86cf "),
U256::from(1000000), );
let tx = SimulationTx {
caller: address!("0x28C6c06298d514Db089934071355E5743bf21d60"),
transact_to: TxKind::Call(usdc),
value: U256::ZERO,
data: transfer_data.into(),
};
let result = &evm
.trace_transactions(SimulationBatch {
is_stateful: false,
transactions: vec![tx],
overrides: None,
})
.into_iter()
.map(|v| v.unwrap())
.collect::<Vec<_>>()[0];
let output = result.0.output().unwrap();
assert!(
output.len() == 32 && output[31] == 1,
"❌ Expected transfer to succeed"
);
for (_, change) in result.1.iter() {
println!("Slot Change on global: {:?}", change);
}
if let Some(call_trace) = result.2.call_trace.as_ref() {
let slot_changes = call_trace.all_slot_accesses(SlotAccessType::Write);
for change in slot_changes {
println!("Slot Change detail: {:?}", change);
}
}
for transfer in &result.2.asset_transfers {
let token_info = &get_token_infos(&mut evm, &[transfer.token]).unwrap()[0];
println!(
"Transfer: {} {} -> {}: {}",
token_info.symbol,
transfer.from,
transfer.to.unwrap(),
format_units(transfer.value, token_info.decimals).unwrap()
);
}
Ok(())
}