Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example for fork + ref_transact impl #296

Merged
merged 4 commits into from
Dec 20, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions examples/fork_ref_transact.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use std::{str::FromStr, sync::Arc};
use anyhow::{Ok, Result};
use bytes::Bytes;
use ethers::{
abi::parse_abi,
prelude::BaseContract,
providers::{Http, Provider},
};
use revm::{
db::{CacheDB, EmptyDB, EthersDB},
Database, TransactOut, TransactTo, B160, EVM, U256 as rU256,
};

#[tokio::main]
async fn main() -> Result<()> {
// create ethers client and wrap it in Arc<M>
let client = Provider::<Http>::try_from(
"https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
)?;
let client = Arc::new(client);

// ----------------------------------------------------------- //
// Storage slots of UniV2Pair contract //
// =========================================================== //
// storage[5] = factory: address //
// storage[6] = token0: address //
// storage[7] = token1: address //
// storage[8] = (res0, res1, ts): (uint112, uint112, uint32) //
// storage[9] = price0CumulativeLast: uint256 //
// storage[10] = price1CumulativeLast: uint256 //
// storage[11] = kLast: uint256 //
// =========================================================== //

// choose slot of storage that you would like to transact with
let slot = rU256::from(8);

// ETH/USDT pair on Uniswap V2
let pool_address = B160::from_str("0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852")?;

// generate abi for the calldata from the human readable interface
let abi = BaseContract::from(
parse_abi(&[
"function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)",
])?
);

// encode abi into Bytes
let encoded = abi.encode("getReserves", ())?;

// initialize new EthersDB
let mut ethersdb = EthersDB::new(Arc::clone(&client), None).unwrap();

// query basic properties of an account incl bytecode
let acc_info = ethersdb.basic(pool_address).unwrap().unwrap();

// query value of storage slot at account address
let value = ethersdb.storage(pool_address, slot).unwrap();

// initialise empty in-memory-db
let mut cache_db = CacheDB::new(EmptyDB::default());

// insert basic account info which was generated via Web3DB with the corresponding address
cache_db.insert_account_info(pool_address, acc_info);

// insert our pre-loaded storage slot to the corresponding contract key (address) in the DB
cache_db
.insert_account_storage(pool_address, slot, value)
.unwrap();

// initialise an empty (default) EVM
let mut evm = EVM::new();

// insert pre-built database from above
evm.database(cache_db);

// fill in missing bits of env struc
// change that to whatever caller you want to be
evm.env.tx.caller = B160::from_str("0x0000000000000000000000000000000000000000")?;
// account you want to transact with
evm.env.tx.transact_to = TransactTo::Call(pool_address);
// calldata formed via abigen
evm.env.tx.data = Bytes::from(hex::decode(hex::encode(&encoded))?);
// transaction value in wei
evm.env.tx.value = rU256::try_from(0)?;

// execute transaction without writing to the DB
let ref_tx = evm.transact_ref();
// select ExecutionResult struct
let result = ref_tx.0;

// unpack output call enum into raw bytes
let value = match result.out {
TransactOut::Call(value) => Some(value),
_ => None,
};

// decode bytes to reserves + ts via ethers-rs's abi decode
let (reserve0, reserve1, ts): (u128, u128, u32) =
abi.decode_output("getReserves", value.unwrap())?;

// Print emualted getReserves() call output
println!("Reserve0: {:#?}", reserve0);
println!("Reserve1: {:#?}", reserve1);
println!("Timestamp: {:#?}", ts);

Ok(())
}