foundry_evm/inspectors/
logs.rs1use 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, 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 was_precompile_called: true,
36 precompile_call_logs: vec![],
37 });
38 }
39 None
40 }
41
42 fn hardhat_log(&mut self, data: &[u8]) -> alloy_sol_types::Result<()> {
43 let decoded = console::hh::ConsoleCalls::abi_decode(data)?;
44 self.logs.push(hh_to_ds(&decoded));
45 Ok(())
46 }
47}
48
49impl<CTX> Inspector<CTX, EthInterpreter> for LogCollector
50where
51 CTX: ContextTr,
52{
53 fn log(&mut self, _context: &mut CTX, log: Log) {
54 self.logs.push(log);
55 }
56
57 fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
58 if inputs.target_address == HARDHAT_CONSOLE_ADDRESS {
59 return self.do_hardhat_log(context, inputs);
60 }
61 None
62 }
63}
64
65impl InspectorExt for LogCollector {
66 fn console_log(&mut self, msg: &str) {
67 self.logs.push(new_console_log(msg));
68 }
69}
70
71fn hh_to_ds(call: &console::hh::ConsoleCalls) -> Log {
73 let msg = call.fmt(Default::default());
75 new_console_log(&msg)
76}
77
78fn new_console_log(msg: &str) -> Log {
80 Log::new_unchecked(
81 HARDHAT_CONSOLE_ADDRESS,
82 vec![console::ds::log::SIGNATURE_HASH],
83 msg.abi_encode().into(),
84 )
85}