1use crate::contract::Event;
5use alloy_primitives::{Address, Bytes, Log, U256};
6use alloy_sol_types::{decode_revert_reason, SolCall, SolEvent};
7use revm::primitives::{ExecutionResult, Output, TransactTo, TxEnv};
8use std::fmt;
9
10#[derive(Debug, Clone)]
12pub struct RevertError {
13 pub function_name: &'static str,
15 sender: Address,
17 pub output: Option<String>,
19}
20
21impl fmt::Display for RevertError {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23 let out_str = match &self.output {
24 Some(x) => x.as_str(),
25 None => "No output",
26 };
27
28 write!(
29 f,
30 "Failed to call {} from {} due to revert: {}",
31 self.function_name, self.sender, out_str,
32 )
33 }
34}
35
36pub fn deployment_output(contract_name: &str, execution_result: ExecutionResult) -> Output {
51 match execution_result {
52 ExecutionResult::Success { output, .. } => output,
53 ExecutionResult::Revert { output, .. } => {
54 panic!(
55 "Failed to deploy {} due to revert: {:?}",
56 contract_name,
57 decode_revert_reason(&output.0)
58 )
59 }
60 ExecutionResult::Halt { reason, .. } => {
61 panic!(
62 "Failed to deploy {} due to halt: {:?}",
63 contract_name, reason
64 )
65 }
66 }
67}
68
69pub fn init_create_transaction(caller: Address, data: Vec<u8>) -> TxEnv {
80 TxEnv {
81 caller,
82 gas_limit: u64::MAX,
83 gas_price: U256::ZERO,
84 gas_priority_fee: None,
85 transact_to: TransactTo::create(),
86 value: U256::ZERO,
87 data: Bytes::from(data),
88 chain_id: None,
89 nonce: None,
90 access_list: Vec::new(),
91 blob_hashes: Vec::default(),
92 max_fee_per_blob_gas: None,
93 }
94}
95
96pub fn init_call_transaction(
109 caller: Address,
110 contract: Address,
111 data: Vec<u8>,
112 value: U256,
113) -> TxEnv {
114 TxEnv {
115 caller,
116 gas_limit: u64::MAX,
117 gas_price: U256::ZERO,
118 gas_priority_fee: None,
119 transact_to: TransactTo::Call(contract),
120 value,
121 data: Bytes::from(data),
122 chain_id: None,
123 nonce: None,
124 access_list: Vec::new(),
125 blob_hashes: Vec::default(),
126 max_fee_per_blob_gas: None,
127 }
128}
129
130pub fn result_to_raw_output(
146 sender: Address,
147 execution_result: ExecutionResult,
148) -> Result<ExecutionResult, RevertError> {
149 match execution_result {
150 ExecutionResult::Success { .. } => Ok(execution_result),
151 ExecutionResult::Revert { output, .. } => Err(RevertError {
152 function_name: "Direct execute raw",
153 sender,
154 output: decode_revert_reason(&output),
155 }),
156 ExecutionResult::Halt { reason, .. } => panic!("Failed due to halt: {:?}", reason),
157 }
158}
159
160pub fn result_to_output_with_events(
187 step: usize,
188 sequence: usize,
189 function_selector: [u8; 4],
190 sender: Address,
191 execution_result: ExecutionResult,
192 checked: bool,
193) -> Event {
194 match execution_result {
195 ExecutionResult::Success { output, logs, .. } => match output {
196 Output::Call(_) => Event {
197 success: true,
198 function_selector,
199 logs,
200 step,
201 sequence,
202 },
203 Output::Create(..) => {
204 panic!("Unexpected call to create contract during simulation.")
205 }
206 },
207 ExecutionResult::Revert { output, .. } => match checked {
208 true => panic!(
209 "Failed to call {:?} from {} due to revert: {:?}",
210 function_selector,
211 sender,
212 decode_revert_reason(&output.0)
213 ),
214 false => Event {
215 success: true,
216 function_selector,
217 logs: Vec::default(),
218 step,
219 sequence,
220 },
221 },
222 ExecutionResult::Halt { reason, .. } => {
223 panic!(
224 "Failed to call {:?} from {} due to halt: {:?}",
225 function_selector, sender, reason
226 )
227 }
228 }
229}
230
231pub fn result_to_output(
245 function_name: &'static str,
246 sender: Address,
247 execution_result: ExecutionResult,
248) -> Result<(Output, Vec<Log>), RevertError> {
249 match execution_result {
250 ExecutionResult::Success { output, logs, .. } => Ok((output, logs)),
251 ExecutionResult::Revert { output, .. } => Err(RevertError {
252 function_name,
253 sender,
254 output: decode_revert_reason(&output),
255 }),
256 ExecutionResult::Halt { reason, .. } => {
257 panic!(
258 "Failed to call {} from {} due to halt: {:?}",
259 function_name, sender, reason
260 )
261 }
262 }
263}
264
265pub fn decode_event<T: SolEvent>(event: &Event) -> (usize, usize, Log<T>) {
276 let log = event.logs.last().unwrap();
277 let decoded_event = T::decode_log(log, false);
278
279 let decoded_event = match decoded_event {
280 Ok(e) => e,
281 Err(_) => panic!("Failed to decode event from {:?}", event.function_selector),
282 };
283
284 (event.step, event.sequence, decoded_event)
285}
286
287pub fn process_events<S: SolCall, T: SolEvent>(events: &[Event]) -> Vec<(usize, usize, Log<T>)> {
294 let function_selector = S::SELECTOR;
295 events
296 .iter()
297 .filter(|x| x.function_selector == function_selector)
298 .map(decode_event)
299 .collect()
300}