1use alloy_evm::Database;
2use alloy_primitives::Address;
3use foundry_common::sh_err;
4use foundry_evm_core::backend::DatabaseError;
5use revm::{
6 bytecode::opcode::ADDRESS,
7 context::ContextTr,
8 inspector::JournalExt,
9 interpreter::{
10 interpreter::EthInterpreter, interpreter_types::Jumps, InstructionResult, Interpreter,
11 },
12 Inspector,
13};
1415/// An inspector that enforces certain rules during script execution.
16///
17/// Currently, it only warns if the `ADDRESS` opcode is used within the script's main contract.
18#[derive(Clone, Debug, Default)]
19pub struct ScriptExecutionInspector {
20/// The address of the script contract being executed.
21pub script_address: Address,
22}
2324impl<CTX, D> Inspector<CTX, EthInterpreter> for ScriptExecutionInspector25where
26D: Database<Error = DatabaseError>,
27 CTX: ContextTr<Db = D>,
28 CTX::Journal: JournalExt,
29{
30#[inline]
31fn step(&mut self, interpreter: &mut Interpreter, _ecx: &mut CTX) {
32// Check if both target and bytecode address are the same as script contract address
33 // (allow calling external libraries when bytecode address is different).
34if interpreter.bytecode.opcode() == ADDRESS &&
35 interpreter.input.target_address == self.script_address &&
36 interpreter.input.bytecode_address == Some(self.script_address)
37 {
38// Log the reason for revert
39let _ = sh_err!(
40"Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon."
41);
42// Set the instruction result to Revert to stop execution
43interpreter.control.instruction_result = InstructionResult::Revert;
44 }
45// Note: We don't return anything here as step returns void.
46 // The original check returned InstructionResult::Continue, but that's the default
47 // behavior.
48}
49}