foundry_evm/inspectors/
logs.rs
1use alloy_primitives::Log;
2use alloy_sol_types::{SolEvent, SolInterface, SolValue};
3use foundry_common::{ErrorExt, fmt::ConsoleFmt};
4use foundry_evm_core::{InspectorExt, abi::console, constants::HARDHAT_CONSOLE_ADDRESS};
5use revm::{
6 Inspector,
7 context::ContextTr,
8 interpreter::{
9 CallInputs, CallOutcome, Gas, InstructionResult, Interpreter, InterpreterResult,
10 interpreter::EthInterpreter,
11 },
12};
13
14#[derive(Clone, Debug, Default)]
18pub struct LogCollector {
19 pub logs: Vec<Log>,
21}
22
23impl LogCollector {
24 #[cold]
25 fn do_hardhat_log<CTX>(&mut self, context: &mut CTX, inputs: &CallInputs) -> Option<CallOutcome>
26 where
27 CTX: ContextTr,
28 {
29 if let Err(err) = self.hardhat_log(&inputs.input.bytes(context)) {
30 let result = InstructionResult::Revert;
31 let output = err.abi_encode_revert();
32 return Some(CallOutcome {
33 result: InterpreterResult { result, output, gas: Gas::new(inputs.gas_limit) },
34 memory_offset: inputs.return_memory_offset.clone(),
35 });
36 }
37 None
38 }
39
40 fn hardhat_log(&mut self, data: &[u8]) -> alloy_sol_types::Result<()> {
41 let decoded = console::hh::ConsoleCalls::abi_decode(data)?;
42 self.logs.push(hh_to_ds(&decoded));
43 Ok(())
44 }
45}
46
47impl<CTX> Inspector<CTX, EthInterpreter> for LogCollector
48where
49 CTX: ContextTr,
50{
51 fn log(&mut self, _interp: &mut Interpreter, _context: &mut CTX, log: Log) {
52 self.logs.push(log);
53 }
54
55 fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
56 if inputs.target_address == HARDHAT_CONSOLE_ADDRESS {
57 return self.do_hardhat_log(context, inputs);
58 }
59 None
60 }
61}
62
63impl InspectorExt for LogCollector {
64 fn console_log(&mut self, msg: &str) {
65 self.logs.push(new_console_log(msg));
66 }
67}
68
69fn hh_to_ds(call: &console::hh::ConsoleCalls) -> Log {
71 let msg = call.fmt(Default::default());
73 new_console_log(&msg)
74}
75
76fn new_console_log(msg: &str) -> Log {
78 Log::new_unchecked(
79 HARDHAT_CONSOLE_ADDRESS,
80 vec![console::ds::log::SIGNATURE_HASH],
81 msg.abi_encode().into(),
82 )
83}