foundry_evm/inspectors/
script.rs

1use alloy_evm::Database;
2use alloy_primitives::{Address, Bytes};
3use foundry_evm_core::backend::DatabaseError;
4use revm::{
5    Inspector,
6    bytecode::opcode::ADDRESS,
7    context::ContextTr,
8    inspector::JournalExt,
9    interpreter::{
10        InstructionResult, Interpreter, InterpreterAction,
11        interpreter::EthInterpreter,
12        interpreter_types::{Jumps, LoopControl},
13    },
14};
15
16/// An inspector that enforces certain rules during script execution.
17///
18/// Currently, it only warns if the `ADDRESS` opcode is used within the script's main contract.
19#[derive(Clone, Debug, Default)]
20pub struct ScriptExecutionInspector {
21    /// The address of the script contract being executed.
22    pub script_address: Address,
23}
24
25impl<CTX, D> Inspector<CTX, EthInterpreter> for ScriptExecutionInspector
26where
27    D: Database<Error = DatabaseError>,
28    CTX: ContextTr<Db = D>,
29    CTX::Journal: JournalExt,
30{
31    fn 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).
34        if interpreter.bytecode.opcode() == ADDRESS
35            && interpreter.input.target_address == self.script_address
36            && interpreter.input.bytecode_address == Some(self.script_address)
37        {
38            interpreter.bytecode.set_action(InterpreterAction::new_return(
39                InstructionResult::Revert,
40                Bytes::from("Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon."),
41                interpreter.gas,
42            ));
43        }
44    }
45}