1use alloy_primitives::{Address, Bytes, Log, U256, map::AddressHashMap};
7use eyre::Result;
8use foundry_evm::{
9 executors::{DeployResult, Executor, RawCallResult},
10 traces::{TraceKind, Traces},
11};
12
13static RUN_SELECTOR: [u8; 4] = [0xc0, 0x40, 0x62, 0x26];
15
16#[derive(Debug)]
21pub struct ChiselRunner {
22 pub executor: Executor,
24 pub initial_balance: U256,
26 pub sender: Address,
28 pub input: Option<Vec<u8>>,
30}
31
32#[derive(Debug, Default)]
34pub struct ChiselResult {
35 pub success: bool,
37 pub logs: Vec<Log>,
39 pub traces: Traces,
41 pub gas_used: u64,
43 pub labeled_addresses: AddressHashMap<String>,
45 pub returned: Bytes,
47 pub address: Address,
49 pub state: Option<(Vec<U256>, Vec<u8>)>,
51}
52
53impl ChiselRunner {
55 pub fn new(
65 executor: Executor,
66 initial_balance: U256,
67 sender: Address,
68 input: Option<Vec<u8>>,
69 ) -> Self {
70 Self { executor, initial_balance, sender, input }
71 }
72
73 pub fn run(&mut self, bytecode: Bytes) -> Result<ChiselResult> {
75 self.executor.set_balance(self.sender, U256::MAX)?;
77
78 let DeployResult { address, .. } = self
81 .executor
82 .deploy(self.sender, bytecode, U256::ZERO, None)
83 .map_err(|err| eyre::eyre!("Failed to deploy REPL contract:\n{}", err))?;
84
85 self.executor.set_balance(self.sender, self.initial_balance)?;
87
88 let mut calldata = RUN_SELECTOR.to_vec();
90 if let Some(mut input) = self.input.clone() {
91 calldata.append(&mut input);
92 }
93
94 let res = self.executor.transact_raw(self.sender, address, calldata.into(), U256::ZERO)?;
95
96 let RawCallResult {
97 result, reverted, logs, traces, labels, chisel_state, gas_used, ..
98 } = res;
99
100 Ok(ChiselResult {
101 returned: result,
102 success: !reverted,
103 gas_used,
104 logs,
105 traces: traces.map(|traces| vec![(TraceKind::Execution, traces)]).unwrap_or_default(),
106 labeled_addresses: labels,
107 address,
108 state: chisel_state,
109 })
110 }
111}