example_erc20_gas/
main.rs1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
6
7use alloy_provider::{network::Ethereum, DynProvider, Provider, ProviderBuilder};
8use alloy_sol_types::SolValue;
9use anyhow::Result;
10use exec::transact_erc20evm_commit;
11use revm::{
12 context::TxEnv,
13 database::{AlloyDB, BlockId, CacheDB},
14 database_interface::WrapDatabaseAsync,
15 primitives::{address, hardfork::SpecId, keccak256, Address, StorageValue, TxKind, U256},
16 state::AccountInfo,
17 Context, Database, MainBuilder, MainContext,
18};
19
20pub mod exec;
22pub mod handler;
24
25type AlloyCacheDB = CacheDB<WrapDatabaseAsync<AlloyDB<Ethereum, DynProvider>>>;
26
27pub const TOKEN: Address = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48");
30pub const TREASURY: Address = address!("0000000000000000000000000000000000000001");
32
33#[tokio::main]
34async fn main() -> Result<()> {
35 let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
37 let provider = ProviderBuilder::new().connect(rpc_url).await?.erased();
38
39 let alloy_db = WrapDatabaseAsync::new(AlloyDB::new(provider, BlockId::latest())).unwrap();
40 let mut cache_db = CacheDB::new(alloy_db);
41
42 let account = address!("18B06aaF27d44B756FCF16Ca20C1f183EB49111f");
44 let account_to = address!("21a4B6F62E51e59274b6Be1705c7c68781B87C77");
46
47 let hundred_tokens = U256::from(100_000_000_000_000_000u128);
49
50 let balance_slot = erc_address_storage(account);
51 println!("Balance slot: {balance_slot}");
52 cache_db
53 .insert_account_storage(TOKEN, balance_slot, hundred_tokens * StorageValue::from(2))
54 .unwrap();
55 cache_db.insert_account_info(
56 account,
57 AccountInfo {
58 balance: hundred_tokens * U256::from(2),
59 ..Default::default()
60 },
61 );
62
63 let balance_before = balance_of(account, &mut cache_db).unwrap();
64 println!("Balance before: {balance_before}");
65
66 transfer(account, account_to, hundred_tokens, &mut cache_db)?;
69
70 let balance_after = balance_of(account, &mut cache_db)?;
71 println!("Balance after: {balance_after}");
72
73 Ok(())
74}
75
76fn balance_of(address: Address, alloy_db: &mut AlloyCacheDB) -> Result<StorageValue> {
77 let slot = erc_address_storage(address);
78 alloy_db.storage(TOKEN, slot).map_err(From::from)
79}
80
81fn transfer(from: Address, to: Address, amount: U256, cache_db: &mut AlloyCacheDB) -> Result<()> {
82 let mut ctx = Context::mainnet()
83 .with_db(cache_db)
84 .modify_cfg_chained(|cfg| {
85 cfg.spec = SpecId::CANCUN;
86 })
87 .with_tx(
88 TxEnv::builder()
89 .caller(from)
90 .kind(TxKind::Call(to))
91 .value(amount)
92 .gas_price(2)
93 .build()
94 .unwrap(),
95 )
96 .modify_block_chained(|b| {
97 b.basefee = 1;
98 })
99 .build_mainnet();
100
101 transact_erc20evm_commit(&mut ctx).unwrap();
102
103 Ok(())
104}
105
106pub fn erc_address_storage(address: Address) -> U256 {
110 keccak256((address, U256::from(4)).abi_encode()).into()
111}