From 8c817791c503ecbec4a1beb1372ae1ac22ea3cac Mon Sep 17 00:00:00 2001 From: Ryan Pate Date: Wed, 20 Dec 2023 12:51:32 -0800 Subject: [PATCH] fix(cheatcodes): Include calls to create2 factory in state diff recording --- crates/cheatcodes/src/inspector.rs | 49 ++++++++++++++++++++++++++++-- crates/forge/tests/it/repros.rs | 3 ++ testdata/repros/Issue6634.t.sol | 35 +++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 testdata/repros/Issue6634.t.sol diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 390c16fb92f5..482efff432ae 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1228,6 +1228,51 @@ impl Inspector for Cheatcodes { let address = self.allow_cheatcodes_on_create(data, call); // If `recordAccountAccesses` has been called, record the create if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack { + let mut create_accessor = call.caller; + let mut create_call_depth = data.journaled_state.depth(); + + let mut base_depth = 1; + if let Some(prank) = &self.prank { + base_depth = prank.depth; + } else if let Some(broadcast) = &self.broadcast { + base_depth = broadcast.depth; + } + + // If the create scheme is Create2 and the depth equals the broadcast/prank/default + // depth, then record an additional call to the create2 factory. + if data.journaled_state.depth() == base_depth { + match call.scheme { + CreateScheme::Create => {} + CreateScheme::Create2 { salt } => { + create_accessor = DEFAULT_CREATE2_DEPLOYER; + create_call_depth += 1; + + let calldata = + [&salt.to_be_bytes::<32>()[..], &call.init_code[..]].concat(); + recorded_account_diffs_stack.push(vec![AccountAccess { + access: crate::Vm::AccountAccess { + chainInfo: crate::Vm::ChainInfo { + forkId: data.db.active_fork_id().unwrap_or_default(), + chainId: U256::from(data.env.cfg.chain_id), + }, + accessor: call.caller, + account: DEFAULT_CREATE2_DEPLOYER, + kind: crate::Vm::AccountAccessKind::Call, + initialized: true, + oldBalance: U256::ZERO, // updated on create_end + newBalance: U256::ZERO, // updated on create_end + value: call.value, + data: calldata, + reverted: false, + deployedCode: vec![], // updated on create_end + storageAccesses: vec![], // updated on create_end + }, + depth: data.journaled_state.depth(), + }]) + } + } + } + // Record the create context as an account access and create a new vector to record all // subsequent account accesses recorded_account_diffs_stack.push(vec![AccountAccess { @@ -1236,7 +1281,7 @@ impl Inspector for Cheatcodes { forkId: data.db.active_fork_id().unwrap_or_default(), chainId: U256::from(data.env.cfg.chain_id), }, - accessor: call.caller, + accessor: create_accessor, account: address, kind: crate::Vm::AccountAccessKind::Create, initialized: true, @@ -1248,7 +1293,7 @@ impl Inspector for Cheatcodes { deployedCode: vec![], // updated on create_end storageAccesses: vec![], // updated on create_end }, - depth: data.journaled_state.depth(), + depth: create_call_depth, }]); } diff --git a/crates/forge/tests/it/repros.rs b/crates/forge/tests/it/repros.rs index 5ea2bd37845c..e1530b24a97f 100644 --- a/crates/forge/tests/it/repros.rs +++ b/crates/forge/tests/it/repros.rs @@ -285,3 +285,6 @@ test_repro!(6554; |config| { cheats_config.fs_permissions.add(PathPermission::read_write(path)); config.runner.cheats_config = std::sync::Arc::new(cheats_config); }); + +// https://github.com/foundry-rs/foundry/issues/6634 +test_repro!(6634); diff --git a/testdata/repros/Issue6634.t.sol b/testdata/repros/Issue6634.t.sol new file mode 100644 index 000000000000..6741020fb9a2 --- /dev/null +++ b/testdata/repros/Issue6634.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity 0.8.18; + +import "ds-test/test.sol"; +import "../cheats/Vm.sol"; + +contract Box { + uint256 public number; + + constructor(uint256 _number) { + number = _number; + } +} + +// https://github.com/foundry-rs/foundry/issues/6634 +contract Issue6634Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function test() public { + address CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + vm.startStateDiffRecording(); + Box a = new Box{salt: 0}(1); + + Vm.AccountAccess[] memory called = vm.stopAndReturnStateDiff(); + assertEq(called.length, 2, "incorrect length"); + assertEq(uint256(called[0].kind), uint256(Vm.AccountAccessKind.Call), "first AccountAccess is incorrect kind"); + assertEq(called[0].account, CREATE2_DEPLOYER, "first AccountAccess accout is incorrect"); + assertEq( + uint256(called[1].kind), uint256(Vm.AccountAccessKind.Create), "second AccountAccess is incorrect kind" + ); + assertEq(called[1].accessor, CREATE2_DEPLOYER, "second AccountAccess accessor is incorrect"); + assertEq(called[1].account, address(a), "first AccountAccess accout is incorrect"); + } +}