diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index aefc5f1c02f5..6d0f168c3859 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -170,6 +170,7 @@ impl CallArgs { config.fork_block_number = Some(block_number); } + let create2_deployer = evm_opts.create2_deployer; let (mut env, fork, chain, alphanet) = TracingExecutor::get_fork_material(&config, evm_opts).await?; @@ -177,8 +178,15 @@ impl CallArgs { env.cfg.disable_block_gas_limit = true; env.block.gas_limit = U256::MAX; - let mut executor = - TracingExecutor::new(env, fork, evm_version, debug, decode_internal, alphanet); + let mut executor = TracingExecutor::new( + env, + fork, + evm_version, + debug, + decode_internal, + alphanet, + create2_deployer, + ); let value = tx.value.unwrap_or_default(); let input = tx.inner.input.into_input().unwrap_or_default(); diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index 79083fa8db9e..09857c9ac15a 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -134,6 +134,7 @@ impl RunArgs { // we need to fork off the parent block config.fork_block_number = Some(tx_block_number - 1); + let create2_deployer = evm_opts.create2_deployer; let (mut env, fork, chain, alphanet) = TracingExecutor::get_fork_material(&config, evm_opts).await?; @@ -166,6 +167,7 @@ impl RunArgs { self.debug, self.decode_internal, alphanet, + create2_deployer, ); let mut env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), executor.spec_id()); diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 6f3acb58c273..447a9e7473ec 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1587,6 +1587,10 @@ impl InspectorExt for Cheatcodes { false } } + + fn create2_deployer(&self) -> Address { + self.config.evm_opts.create2_deployer + } } impl Cheatcodes { diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 6444802e3bc9..3791eb42d6fd 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -440,6 +440,9 @@ pub struct Config { /// CREATE2 salt to use for the library deployment in scripts. pub create2_library_salt: B256, + /// The CREATE2 deployer address to use. + pub create2_deployer: Address, + /// Configuration for Vyper compiler pub vyper: VyperConfig, @@ -553,6 +556,10 @@ impl Config { /// Default salt for create2 library deployments pub const DEFAULT_CREATE2_LIBRARY_SALT: FixedBytes<32> = FixedBytes::<32>::ZERO; + /// Default create2 deployer + pub const DEFAULT_CREATE2_DEPLOYER: Address = + address!("4e59b44847b379578588920ca78fbf26c0b4956c"); + /// Docker image with eof-enabled solc binary pub const EOF_SOLC_IMAGE: &'static str = "ghcr.io/paradigmxyz/forge-eof@sha256:46f868ce5264e1190881a3a335d41d7f42d6f26ed20b0c823609c715e38d603f"; @@ -2301,6 +2308,7 @@ impl Default for Config { labels: Default::default(), unchecked_cheatcode_artifacts: false, create2_library_salt: Self::DEFAULT_CREATE2_LIBRARY_SALT, + create2_deployer: Self::DEFAULT_CREATE2_DEPLOYER, skip: vec![], dependencies: Default::default(), soldeer: Default::default(), diff --git a/crates/evm/core/src/lib.rs b/crates/evm/core/src/lib.rs index 1a2ac4c4a0f4..0bdc34cc92ce 100644 --- a/crates/evm/core/src/lib.rs +++ b/crates/evm/core/src/lib.rs @@ -5,6 +5,8 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +use crate::constants::DEFAULT_CREATE2_DEPLOYER; +use alloy_primitives::Address; use auto_impl::auto_impl; use backend::DatabaseExt; use revm::{inspectors::NoOpInspector, interpreter::CreateInputs, EvmContext, Inspector}; @@ -54,6 +56,11 @@ pub trait InspectorExt: for<'a> Inspector<&'a mut dyn DatabaseExt> { fn is_alphanet(&self) -> bool { false } + + /// Returns the CREATE2 deployer address. + fn create2_deployer(&self) -> Address { + DEFAULT_CREATE2_DEPLOYER + } } impl InspectorExt for NoOpInspector {} diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index 9849fd1cef9c..f495996cf60b 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -1,5 +1,5 @@ use super::fork::environment; -use crate::fork::CreateFork; +use crate::{constants::DEFAULT_CREATE2_DEPLOYER, fork::CreateFork}; use alloy_primitives::{Address, B256, U256}; use alloy_provider::{network::AnyRpcBlock, Provider}; use eyre::WrapErr; @@ -9,7 +9,7 @@ use revm::primitives::{BlockEnv, CfgEnv, TxEnv}; use serde::{Deserialize, Deserializer, Serialize}; use url::Url; -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct EvmOpts { /// The EVM environment configuration. #[serde(flatten)] @@ -66,6 +66,34 @@ pub struct EvmOpts { /// whether to enable Alphanet features. pub alphanet: bool, + + /// The CREATE2 deployer's address. + pub create2_deployer: Address, +} + +impl Default for EvmOpts { + fn default() -> Self { + Self { + env: Env::default(), + fork_url: None, + fork_block_number: None, + fork_retries: None, + fork_retry_backoff: None, + compute_units_per_second: None, + no_rpc_rate_limit: false, + no_storage_caching: false, + initial_balance: U256::default(), + sender: Address::default(), + ffi: false, + always_use_create_2_factory: false, + verbosity: 0, + memory_limit: 0, + isolate: false, + disable_block_gas_limit: false, + alphanet: false, + create2_deployer: DEFAULT_CREATE2_DEPLOYER, + } + } } impl EvmOpts { diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index be9660c72ac4..5b3bd0ed26e3 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -1,8 +1,5 @@ pub use crate::ic::*; -use crate::{ - backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER, precompiles::ALPHANET_P256, - InspectorExt, -}; +use crate::{backend::DatabaseExt, precompiles::ALPHANET_P256, InspectorExt}; use alloy_consensus::BlockHeader; use alloy_json_abi::{Function, JsonAbi}; use alloy_network::AnyTxEnvelope; @@ -149,12 +146,16 @@ pub fn gas_used(spec: SpecId, spent: u64, refunded: u64) -> u64 { spent - (refunded).min(spent / refund_quotient) } -fn get_create2_factory_call_inputs(salt: U256, inputs: CreateInputs) -> CallInputs { +fn get_create2_factory_call_inputs( + salt: U256, + inputs: CreateInputs, + deployer: Address, +) -> CallInputs { let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code[..]].concat(); CallInputs { caller: inputs.caller, - bytecode_address: DEFAULT_CREATE2_DEPLOYER, - target_address: DEFAULT_CREATE2_DEPLOYER, + bytecode_address: deployer, + target_address: deployer, scheme: CallScheme::Call, value: CallValue::Transfer(inputs.value), input: calldata.into(), @@ -165,7 +166,7 @@ fn get_create2_factory_call_inputs(salt: U256, inputs: CreateInputs) -> CallInpu } } -/// Used for routing certain CREATE2 invocations through [DEFAULT_CREATE2_DEPLOYER]. +/// Used for routing certain CREATE2 invocations through CREATE2_DEPLOYER. /// /// Overrides create hook with CALL frame if [InspectorExt::should_use_create2_factory] returns /// true. Keeps track of overridden frames and handles outcome in the overridden insert_call_outcome @@ -190,8 +191,10 @@ pub fn create2_handler_register( let gas_limit = inputs.gas_limit; + // Get CREATE2 deployer. + let create2_deployer = ctx.external.create2_deployer(); // Generate call inputs for CREATE2 factory. - let mut call_inputs = get_create2_factory_call_inputs(salt, *inputs); + let mut call_inputs = get_create2_factory_call_inputs(salt, *inputs, create2_deployer); // Call inspector to change input or return outcome. let outcome = ctx.external.call(&mut ctx.evm, &mut call_inputs); @@ -202,12 +205,12 @@ pub fn create2_handler_register( .push((ctx.evm.journaled_state.depth(), call_inputs.clone())); // Sanity check that CREATE2 deployer exists. - let code_hash = ctx.evm.load_account(DEFAULT_CREATE2_DEPLOYER)?.info.code_hash; + let code_hash = ctx.evm.load_account(create2_deployer)?.info.code_hash; if code_hash == KECCAK_EMPTY { return Ok(FrameOrResult::Result(FrameResult::Call(CallOutcome { result: InterpreterResult { result: InstructionResult::Revert, - output: "missing CREATE2 deployer".into(), + output: format!("missing CREATE2 deployer: {create2_deployer}").into(), gas: Gas::new(gas_limit), }, memory_offset: 0..0, diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index b5b31b812298..8aacff3d01c1 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -24,6 +24,7 @@ use foundry_evm_core::{ }, decode::{RevertDecoder, SkipReason}, utils::StateChangeset, + InspectorExt, }; use foundry_evm_coverage::HitMaps; use foundry_evm_traces::{SparsedTraceArena, TraceMode}; @@ -237,6 +238,17 @@ impl Executor { self } + #[inline] + pub fn set_create2_deployer(&mut self, create2_deployer: Address) -> &mut Self { + self.inspector_mut().set_create2_deployer(create2_deployer); + self + } + + #[inline] + pub fn create2_deployer(&self) -> Address { + self.inspector().create2_deployer() + } + /// Deploys a contract and commits the new state to the underlying database. /// /// Executes a CREATE transaction with the contract `code` and persistent database state diff --git a/crates/evm/evm/src/executors/trace.rs b/crates/evm/evm/src/executors/trace.rs index 69c68442b65c..de40a17f9e00 100644 --- a/crates/evm/evm/src/executors/trace.rs +++ b/crates/evm/evm/src/executors/trace.rs @@ -1,4 +1,5 @@ use crate::executors::{Executor, ExecutorBuilder}; +use alloy_primitives::Address; use foundry_compilers::artifacts::EvmVersion; use foundry_config::{utils::evm_spec_id, Chain, Config}; use foundry_evm_core::{backend::Backend, fork::CreateFork, opts::EvmOpts}; @@ -19,6 +20,7 @@ impl TracingExecutor { debug: bool, decode_internal: bool, alphanet: bool, + create2_deployer: Address, ) -> Self { let db = Backend::spawn(fork); let trace_mode = @@ -31,7 +33,12 @@ impl TracingExecutor { // configures a bare version of the evm executor: no cheatcode inspector is enabled, // tracing will be enabled only for the targeted transaction executor: ExecutorBuilder::new() - .inspectors(|stack| stack.trace_mode(trace_mode).alphanet(alphanet)) + .inspectors(|stack| { + stack + .trace_mode(trace_mode) + .alphanet(alphanet) + .create2_deployer(create2_deployer) + }) .spec(evm_spec_id(&version.unwrap_or_default(), alphanet)) .build(env, db), } diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index 403e906f6323..accbca4fd59c 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -59,6 +59,8 @@ pub struct InspectorStackBuilder { pub alphanet: bool, /// The wallets to set in the cheatcodes context. pub wallets: Option, + /// The CREATE2 deployer address. + pub create2_deployer: Address, } impl InspectorStackBuilder { @@ -156,6 +158,12 @@ impl InspectorStackBuilder { self } + #[inline] + pub fn create2_deployer(mut self, create2_deployer: Address) -> Self { + self.create2_deployer = create2_deployer; + self + } + /// Builds the stack of inspectors to use when transacting/committing on the EVM. pub fn build(self) -> InspectorStack { let Self { @@ -171,6 +179,7 @@ impl InspectorStackBuilder { enable_isolation, alphanet, wallets, + create2_deployer, } = self; let mut stack = InspectorStack::new(); @@ -197,6 +206,7 @@ impl InspectorStackBuilder { stack.enable_isolation(enable_isolation); stack.alphanet(alphanet); + stack.set_create2_deployer(create2_deployer); // environment, must come after all of the inspectors if let Some(block) = block { @@ -282,6 +292,7 @@ pub struct InspectorStackInner { pub tracer: Option, pub enable_isolation: bool, pub alphanet: bool, + pub create2_deployer: Address, /// Flag marking if we are in the inner EVM context. pub in_inner_context: bool, @@ -398,6 +409,12 @@ impl InspectorStack { self.alphanet = yes; } + /// Set the CREATE2 deployer address. + #[inline] + pub fn set_create2_deployer(&mut self, deployer: Address) { + self.create2_deployer = deployer; + } + /// Set whether to enable the log collector. #[inline] pub fn collect_logs(&mut self, yes: bool) { @@ -1022,6 +1039,10 @@ impl InspectorExt for InspectorStackRefMut<'_> { fn is_alphanet(&self) -> bool { self.inner.alphanet } + + fn create2_deployer(&self) -> Address { + self.inner.create2_deployer + } } impl Inspector<&mut dyn DatabaseExt> for InspectorStack { @@ -1124,6 +1145,10 @@ impl InspectorExt for InspectorStack { fn is_alphanet(&self) -> bool { self.alphanet } + + fn create2_deployer(&self) -> Address { + self.create2_deployer + } } impl<'a> Deref for InspectorStackRefMut<'a> { diff --git a/crates/forge/src/multi_runner.rs b/crates/forge/src/multi_runner.rs index a9f2a93eb37a..0c95716c1027 100644 --- a/crates/forge/src/multi_runner.rs +++ b/crates/forge/src/multi_runner.rs @@ -259,6 +259,7 @@ impl MultiContractRunner { .coverage(self.coverage) .enable_isolation(self.isolation) .alphanet(self.alphanet) + .create2_deployer(self.evm_opts.create2_deployer) }) .spec(self.evm_spec) .gas_limit(self.evm_opts.gas_limit()) diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index db87a85ba0d1..c5c4df70fdce 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -143,6 +143,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { isolate: true, unchecked_cheatcode_artifacts: false, create2_library_salt: Config::DEFAULT_CREATE2_LIBRARY_SALT, + create2_deployer: Config::DEFAULT_CREATE2_DEPLOYER, vyper: Default::default(), skip: vec![], dependencies: Default::default(), diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 82c61ccbc388..d8c39ad088ae 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -854,6 +854,46 @@ forgetest_async!(can_deploy_with_create2, |prj, cmd| { .run(ScriptOutcome::ScriptFailed); }); +forgetest_async!(can_deploy_with_custom_create2, |prj, cmd| { + let (api, handle) = spawn(NodeConfig::test()).await; + let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root()); + let create2 = Address::from_str("0x0000000000000000000000000000000000b4956c").unwrap(); + + // Prepare CREATE2 Deployer + api.anvil_set_code( + create2, + Bytes::from_static(foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE), + ) + .await + .unwrap(); + + tester + .add_deployer(0) + .load_private_keys(&[0]) + .await + .add_create2_deployer(create2) + .add_sig("BroadcastTestNoLinking", "deployCreate2()") + .simulate(ScriptOutcome::OkSimulation) + .broadcast(ScriptOutcome::OkBroadcast) + .assert_nonce_increment(&[(0, 2)]) + .await; +}); + +forgetest_async!(canot_deploy_with_nonexist_create2, |prj, cmd| { + let (_api, handle) = spawn(NodeConfig::test()).await; + let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root()); + let create2 = Address::from_str("0x0000000000000000000000000000000000b4956c").unwrap(); + + tester + .add_deployer(0) + .load_private_keys(&[0]) + .await + .add_create2_deployer(create2) + .add_sig("BroadcastTestNoLinking", "deployCreate2()") + .simulate(ScriptOutcome::ScriptFailed) + .broadcast(ScriptOutcome::ScriptFailed); +}); + forgetest_async!(can_deploy_and_simulate_25_txes_concurrently, |prj, cmd| { let (_api, handle) = spawn(NodeConfig::test()).await; let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root()); @@ -1924,7 +1964,7 @@ contract SimpleScript is Script { ]); cmd.assert_failure().stderr_eq(str![[r#" -Error: script failed: missing CREATE2 deployer +Error: script failed: missing CREATE2 deployer: 0x4e59b44847b379578588920cA78FbF26c0B4956C "#]]); }); diff --git a/crates/script/src/build.rs b/crates/script/src/build.rs index ef42740841b2..052e78e10781 100644 --- a/crates/script/src/build.rs +++ b/crates/script/src/build.rs @@ -17,7 +17,7 @@ use foundry_compilers::{ utils::source_files_iter, ArtifactId, ProjectCompileOutput, }; -use foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, traces::debug::ContractSources}; +use foundry_evm::traces::debug::ContractSources; use foundry_linking::Linker; use std::{path::PathBuf, str::FromStr, sync::Arc}; @@ -40,9 +40,10 @@ impl BuildData { /// Links contracts. Uses CREATE2 linking when possible, otherwise falls back to /// default linking with sender nonce and address. pub async fn link(self, script_config: &ScriptConfig) -> Result { + let create2_deployer = script_config.evm_opts.create2_deployer; let can_use_create2 = if let Some(fork_url) = &script_config.evm_opts.fork_url { let provider = try_get_http_provider(fork_url)?; - let deployer_code = provider.get_code_at(DEFAULT_CREATE2_DEPLOYER).await?; + let deployer_code = provider.get_code_at(create2_deployer).await?; !deployer_code.is_empty() } else { @@ -57,7 +58,7 @@ impl BuildData { self.get_linker() .link_with_create2( known_libraries.clone(), - DEFAULT_CREATE2_DEPLOYER, + create2_deployer, script_config.config.create2_library_salt, &self.target, ) diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index 0f0283b9f01a..3f507bd613d0 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -46,7 +46,6 @@ use foundry_config::{ }; use foundry_evm::{ backend::Backend, - constants::DEFAULT_CREATE2_DEPLOYER, executors::ExecutorBuilder, inspectors::{ cheatcodes::{BroadcastableTransactions, Wallets}, @@ -199,6 +198,10 @@ pub struct ScriptArgs { )] pub with_gas_price: Option, + /// The CREATE2 deployer address to use, this will override the one in the config. + #[arg(long, value_name = "ADDRESS")] + pub create2_deployer: Option
, + /// Timeout to use for broadcasting transactions. #[arg(long, env = "ETH_TIMEOUT")] pub timeout: Option, @@ -230,6 +233,10 @@ impl ScriptArgs { evm_opts.sender = sender; } + if let Some(create2_deployer) = self.create2_deployer { + evm_opts.create2_deployer = create2_deployer; + } + let script_config = ScriptConfig::new(config, evm_opts).await?; Ok(PreprocessedState { args: self, script_config, script_wallets }) @@ -239,7 +246,9 @@ impl ScriptArgs { pub async fn run_script(self) -> Result<()> { trace!(target: "script", "executing script command"); - let compiled = self.preprocess().await?.compile()?; + let state = self.preprocess().await?; + let create2_deployer = state.script_config.evm_opts.create2_deployer; + let compiled = state.compile()?; // Move from `CompiledState` to `BundledState` either by resuming or executing and // simulating script. @@ -291,9 +300,10 @@ impl ScriptArgs { pre_simulation.args.check_contract_sizes( &pre_simulation.execution_result, &pre_simulation.build_data.known_contracts, + create2_deployer, )?; - pre_simulation.fill_metadata().await?.bundle().await? + pre_simulation.fill_metadata(create2_deployer).await?.bundle().await? }; // Exit early in case user didn't provide any broadcast/verify related flags. @@ -379,6 +389,7 @@ impl ScriptArgs { &self, result: &ScriptResult, known_contracts: &ContractsByArtifact, + create2_deployer: Address, ) -> Result<()> { // (name, &init, &deployed)[] let mut bytecodes: Vec<(String, &[u8], &[u8])> = vec![]; @@ -423,7 +434,7 @@ impl ScriptArgs { // Find if it's a CREATE or CREATE2. Otherwise, skip transaction. if let Some(TxKind::Call(to)) = to { - if to == DEFAULT_CREATE2_DEPLOYER { + if to == create2_deployer { // Size of the salt prefix. offset = 32; } else { @@ -548,6 +559,7 @@ impl ScriptConfig { // dapptools compatibility 1 }; + Ok(Self { config, evm_opts, sender_nonce, backends: HashMap::default() }) } @@ -607,6 +619,7 @@ impl ScriptConfig { stack .trace_mode(if debug { TraceMode::Debug } else { TraceMode::Call }) .alphanet(self.evm_opts.alphanet) + .create2_deployer(self.evm_opts.create2_deployer) }) .spec(self.config.evm_spec_id()) .gas_limit(self.evm_opts.gas_limit()) diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index fa8ff19d9a9d..08478eec6451 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -7,7 +7,7 @@ use eyre::Result; use foundry_cheatcodes::BroadcastableTransaction; use foundry_config::Config; use foundry_evm::{ - constants::{CALLER, DEFAULT_CREATE2_DEPLOYER}, + constants::CALLER, executors::{DeployResult, EvmError, ExecutionErr, Executor, RawCallResult}, opts::EvmOpts, revm::interpreter::{return_ok, InstructionResult}, @@ -50,6 +50,9 @@ impl ScriptRunner { } } + // set CREATE2 deployer from EvmOpts. + self.executor.set_create2_deployer(self.evm_opts.create2_deployer); + self.executor.set_nonce(self.evm_opts.sender, sender_nonce)?; // We max out their balance so that they can deploy and make calls. @@ -83,9 +86,9 @@ impl ScriptRunner { }) }), ScriptPredeployLibraries::Create2(libraries, salt) => { + let create2_deployer = self.executor.create2_deployer(); for library in libraries { - let address = - DEFAULT_CREATE2_DEPLOYER.create2_from_code(salt, library.as_ref()); + let address = create2_deployer.create2_from_code(salt, library.as_ref()); // Skip if already deployed if !self.executor.is_empty_code(address)? { continue; @@ -95,7 +98,7 @@ impl ScriptRunner { .executor .transact_raw( self.evm_opts.sender, - DEFAULT_CREATE2_DEPLOYER, + create2_deployer, calldata.clone().into(), U256::from(0), ) @@ -111,7 +114,7 @@ impl ScriptRunner { from: Some(self.evm_opts.sender), input: calldata.into(), nonce: Some(sender_nonce + library_transactions.len() as u64), - to: Some(TxKind::Call(DEFAULT_CREATE2_DEPLOYER)), + to: Some(TxKind::Call(create2_deployer)), ..Default::default() } .into(), diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index 95427225f202..d2be1b1181e0 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -46,7 +46,7 @@ impl PreSimulationState { /// left empty. /// /// Both modes will panic if any of the transactions have None for the `rpc` field. - pub async fn fill_metadata(self) -> Result { + pub async fn fill_metadata(self, create2_deployer: Address) -> Result { let address_to_abi = self.build_address_to_abi_map(); let mut transactions = self @@ -64,7 +64,11 @@ impl PreSimulationState { let mut builder = ScriptTransactionBuilder::new(tx.transaction, rpc); if let Some(TxKind::Call(_)) = to { - builder.set_call(&address_to_abi, &self.execution_artifacts.decoder)?; + builder.set_call( + &address_to_abi, + &self.execution_artifacts.decoder, + create2_deployer, + )?; } else { builder.set_create(false, sender.create(nonce), &address_to_abi)?; } diff --git a/crates/script/src/transaction.rs b/crates/script/src/transaction.rs index ca6a6226949c..2cf480b9bd0a 100644 --- a/crates/script/src/transaction.rs +++ b/crates/script/src/transaction.rs @@ -4,7 +4,7 @@ use alloy_primitives::{hex, Address, TxKind, B256}; use eyre::Result; use forge_script_sequence::TransactionWithMetadata; use foundry_common::{fmt::format_token_raw, ContractData, TransactionMaybeSigned, SELECTOR_LEN}; -use foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, traces::CallTraceDecoder}; +use foundry_evm::traces::CallTraceDecoder; use itertools::Itertools; use revm_inspectors::tracing::types::CallKind; use std::collections::BTreeMap; @@ -29,16 +29,16 @@ impl ScriptTransactionBuilder { &mut self, local_contracts: &BTreeMap, decoder: &CallTraceDecoder, + create2_deployer: Address, ) -> Result<()> { if let Some(TxKind::Call(to)) = self.transaction.transaction.to() { - if to == DEFAULT_CREATE2_DEPLOYER { + if to == create2_deployer { if let Some(input) = self.transaction.transaction.input() { let (salt, init_code) = input.split_at(32); self.set_create( true, - DEFAULT_CREATE2_DEPLOYER - .create2_from_code(B256::from_slice(salt), init_code), + create2_deployer.create2_from_code(B256::from_slice(salt), init_code), local_contracts, )?; } diff --git a/crates/test-utils/src/script.rs b/crates/test-utils/src/script.rs index f15e91d5af78..b82126d2db28 100644 --- a/crates/test-utils/src/script.rs +++ b/crates/test-utils/src/script.rs @@ -171,6 +171,10 @@ impl ScriptTester { self.args(&["--tc", contract_name, "--sig", sig]) } + pub fn add_create2_deployer(&mut self, create2_deployer: Address) -> &mut Self { + self.args(&["--create2-deployer", create2_deployer.to_string().as_str()]) + } + /// Adds the `--unlocked` flag pub fn unlocked(&mut self) -> &mut Self { self.arg("--unlocked") diff --git a/crates/verify/src/utils.rs b/crates/verify/src/utils.rs index a14d6af6df96..06c8bd2d66f1 100644 --- a/crates/verify/src/utils.rs +++ b/crates/verify/src/utils.rs @@ -325,6 +325,7 @@ pub async fn get_tracing_executor( fork_config.fork_block_number = Some(fork_blk_num); fork_config.evm_version = evm_version; + let create2_deployer = evm_opts.create2_deployer; let (env, fork, _chain, is_alphanet) = TracingExecutor::get_fork_material(fork_config, evm_opts).await?; @@ -335,6 +336,7 @@ pub async fn get_tracing_executor( false, false, is_alphanet, + create2_deployer, ); Ok((env, executor))