1use alloy_primitives::{Address, Bytes, Log, U256, map::AddressHashMap};
7use eyre::Result;
8use foundry_evm::{
9 core::evm::EthEvmNetwork,
10 executors::{DeployResult, Executor, RawCallResult},
11 traces::{TraceKind, Traces},
12};
13
14static RUN_SELECTOR: [u8; 4] = [0xc0, 0x40, 0x62, 0x26];
16
17#[derive(Debug)]
22pub struct ChiselRunner {
23 pub executor: Executor<EthEvmNetwork>,
25 pub initial_balance: U256,
27 pub sender: Address,
29 pub input: Option<Vec<u8>>,
31}
32
33#[derive(Debug, Default)]
35pub struct ChiselResult {
36 pub success: bool,
38 pub logs: Vec<Log>,
40 pub traces: Traces,
42 pub gas_used: u64,
44 pub labeled_addresses: AddressHashMap<String>,
46 pub returned: Bytes,
48 pub address: Address,
50 pub state: Option<(Vec<U256>, Vec<u8>)>,
52}
53
54impl ChiselRunner {
56 pub fn new(
66 executor: Executor<EthEvmNetwork>,
67 initial_balance: U256,
68 sender: Address,
69 input: Option<Vec<u8>>,
70 ) -> Self {
71 Self { executor, initial_balance, sender, input }
72 }
73
74 pub fn run(&mut self, bytecode: Bytes) -> Result<ChiselResult> {
76 self.executor.set_balance(self.sender, U256::MAX)?;
78
79 let DeployResult { address, .. } = self
82 .executor
83 .deploy(self.sender, bytecode, U256::ZERO, None)
84 .map_err(|err| eyre::eyre!("Failed to deploy REPL contract:\n{}", err))?;
85
86 self.executor.set_balance(self.sender, self.initial_balance)?;
88
89 let mut calldata = RUN_SELECTOR.to_vec();
91 if let Some(mut input) = self.input.clone() {
92 calldata.append(&mut input);
93 }
94
95 let res = self.executor.transact_raw(self.sender, address, calldata.into(), U256::ZERO)?;
96
97 let RawCallResult {
98 result, reverted, logs, traces, labels, chisel_state, gas_used, ..
99 } = res;
100
101 Ok(ChiselResult {
102 returned: result,
103 success: !reverted,
104 gas_used,
105 logs,
106 traces: traces.map(|traces| vec![(TraceKind::Execution, traces)]).unwrap_or_default(),
107 labeled_addresses: labels,
108 address,
109 state: chisel_state,
110 })
111 }
112}