From 22037659a19e565a67bbda93319a95c312546926 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:07:48 +0000 Subject: [PATCH 1/3] refactor: consolidate DummyCaller contracts into single generic implementation Replaces 7 nearly-identical DummyCaller contracts with a single generic implementation that uses a fallback() function to forward any call. Changes: - Add scripts/libraries/DummyCaller.sol with generic delegatecall forwarder - Update UpgradeOPChain.s.sol to use generic DummyCaller - Update UpgradeSuperchainConfig.s.sol to use generic DummyCaller - Update AddGameType.s.sol to use generic DummyCaller - Update InteropMigration.s.sol to use generic DummyCaller - Remove redundant DummyCallerV1, DummyCallerV2, and DummyCaller contracts The generic DummyCaller reads the target address from storage slot 0, forwards calldata via delegatecall, reverts on failure, and returns on success. This is functionally equivalent to the previous implementations since all callers required success anyway. Closes #18784 Co-Authored-By: Kelvin Fichter --- .../scripts/deploy/AddGameType.s.sol | 32 +++------- .../scripts/deploy/InteropMigration.s.sol | 23 ++----- .../scripts/deploy/UpgradeOPChain.s.sol | 60 ++++--------------- .../deploy/UpgradeSuperchainConfig.s.sol | 55 ++++------------- .../scripts/libraries/DummyCaller.sol | 24 ++++++++ 5 files changed, 61 insertions(+), 133 deletions(-) create mode 100644 packages/contracts-bedrock/scripts/libraries/DummyCaller.sol diff --git a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol index 07579ed32166e..371a60d988df8 100644 --- a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol @@ -6,6 +6,7 @@ import { Script } from "forge-std/Script.sol"; // Scripts import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; // Interfaces import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; @@ -56,10 +57,12 @@ contract AddGameType is Script { } function run(Input memory _agi) public returns (Output memory) { - // Etch DummyCaller contract + // Etch DummyCaller contract. This contract is used to mimic the contract that is used + // as the source of the delegatecall to the OPCM. In practice this will be the governance + // 2/2 or similar. address prank = _agi.prank; - bytes memory code = vm.getDeployedCode("AddGameType.s.sol:DummyCaller"); + bytes memory code = vm.getDeployedCode("DummyCaller.sol:DummyCaller"); vm.etch(prank, code); vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(_agi.opcmImpl))))); vm.label(prank, "DummyCaller"); @@ -81,14 +84,12 @@ contract AddGameType is Script { permissioned: _agi.permissioned }); - // Call into the DummyCaller to perform the delegatecall + // Call into the DummyCaller to perform the delegatecall. + // The DummyCaller uses a fallback that reverts on failure, so no need to check success. vm.broadcast(msg.sender); - - (bool success, bytes memory result) = DummyCaller(prank).addGameType(gameConfigs); - require(success, "AddGameType: addGameType failed"); + IOPContractsManager.AddGameOutput[] memory outputs = IOPContractsManager(prank).addGameType(gameConfigs); // Decode the result and set it in the output - IOPContractsManager.AddGameOutput[] memory outputs = abi.decode(result, (IOPContractsManager.AddGameOutput[])); require(outputs.length == 1, "AddGameType: unexpected number of outputs"); return Output({ delayedWETHProxy: outputs[0].delayedWETH, faultDisputeGameProxy: outputs[0].faultDisputeGame }); } @@ -98,20 +99,3 @@ contract AddGameType is Script { DeployUtils.assertValidContractAddress(address(_ago.faultDisputeGameProxy)); } } - -/// @title DummyCaller -/// @notice This contract is used to mimic the contract that is used as the source of the delegatecall to the OPCM. -/// @dev This contract is used for OPCM versions 4.1.0 and above. - -contract DummyCaller { - address internal _opcmAddr; - - function addGameType(IOPContractsManager.AddGameInput[] memory _gameConfigs) - external - returns (bool, bytes memory) - { - bytes memory data = abi.encodeCall(DummyCaller.addGameType, _gameConfigs); - (bool success, bytes memory result) = _opcmAddr.delegatecall(data); - return (success, result); - } -} diff --git a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol index 8e0517df54b66..48ac77d541634 100644 --- a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol @@ -6,6 +6,7 @@ import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { IOPContractsManagerInteropMigrator, IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { Duration, Proposal, Hash } from "src/dispute/lib/Types.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; @@ -194,16 +195,15 @@ contract InteropMigration is Script { // as the source of the delegatecall to the OPCM. In practice this will be the governance // 2/2 or similar. address prank = _imi.prank(); - bytes memory code = vm.getDeployedCode("InteropMigration.s.sol:DummyCaller"); + bytes memory code = vm.getDeployedCode("DummyCaller.sol:DummyCaller"); vm.etch(prank, code); vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(opcm))))); vm.label(prank, "DummyCaller"); - // Call into the DummyCaller. This will perform the delegatecall under the hood and - // return the result. + // Call into the DummyCaller. This will perform the delegatecall under the hood. + // The DummyCaller uses a fallback that reverts on failure, so no need to check success. vm.broadcast(msg.sender); - (bool success,) = DummyCaller(prank).migrate(inputs); - require(success, "InteropMigration: migrate failed"); + IOPContractsManagerInteropMigrator(prank).migrate(inputs); // After migration all portals will have the same DGF IOptimismPortal portal = IOptimismPortal(payable(opChainConfigs[0].systemConfigProxy.optimismPortal())); @@ -225,16 +225,3 @@ contract InteropMigration is Script { } } } - -contract DummyCaller { - address internal _opcmAddr; - - function migrate(IOPContractsManagerInteropMigrator.MigrateInput memory _migrateInput) - external - returns (bool, bytes memory) - { - bytes memory data = abi.encodeCall(DummyCaller.migrate, _migrateInput); - (bool success, bytes memory result) = _opcmAddr.delegatecall(data); - return (success, result); - } -} diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol index d180f80ffdc23..b0283b82807e6 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol @@ -6,6 +6,7 @@ import { OPContractsManager } from "src/L1/OPContractsManager.sol"; import { OPContractsManagerV2 } from "src/L1/opcm/OPContractsManagerV2.sol"; import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; contract UpgradeOPChainInput is BaseDeployIO { address internal _prank; @@ -80,23 +81,21 @@ contract UpgradeOPChain is Script { // as the source of the delegatecall to the OPCM. In practice this will be the governance // 2/2 or similar. address prank = _uoci.prank(); - bytes memory code = _getDummyCallerCode(useOPCMv2); + bytes memory code = _getDummyCallerCode(); vm.etch(prank, code); vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(opcm))))); vm.label(prank, "DummyCaller"); - // Call into the DummyCaller. This will perform the delegatecall under the hood and - // return the result. - (bool success,) = _upgrade(prank, useOPCMv2, _uoci.upgradeInput()); - require(success, "UpgradeChain: upgrade failed"); + // Call into the DummyCaller. This will perform the delegatecall under the hood. + // The DummyCaller uses a fallback that reverts on failure, so no need to check success. + vm.broadcast(msg.sender); + _upgrade(prank, useOPCMv2, _uoci.upgradeInput()); } - /// @notice Helper function to get the proper dummy caller code based on the OPCM version. - /// @param _useOPCMv2 Whether to use OPCM v2. + /// @notice Helper function to get the dummy caller code. /// @return code The code of the dummy caller. - function _getDummyCallerCode(bool _useOPCMv2) internal view returns (bytes memory) { - if (_useOPCMv2) return vm.getDeployedCode("UpgradeOPChain.s.sol:DummyCallerV2"); - else return vm.getDeployedCode("UpgradeOPChain.s.sol:DummyCallerV1"); + function _getDummyCallerCode() internal view returns (bytes memory) { + return vm.getDeployedCode("DummyCaller.sol:DummyCaller"); } /// @notice Helper function to upgrade the OPCM based on the OPCM version. Performs the decoding of the upgrade @@ -104,46 +103,11 @@ contract UpgradeOPChain is Script { /// @param _prank The address of the dummy caller contract. /// @param _useOPCMv2 Whether to use OPCM v2. /// @param _upgradeInput The upgrade input. - /// @return success Whether the upgrade succeeded. - /// @return result The result of the upgrade (bool, bytes memory). - function _upgrade( - address _prank, - bool _useOPCMv2, - bytes memory _upgradeInput - ) - internal - returns (bool, bytes memory) - { - vm.broadcast(msg.sender); + function _upgrade(address _prank, bool _useOPCMv2, bytes memory _upgradeInput) internal { if (_useOPCMv2) { - return DummyCallerV2(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput))); + OPContractsManagerV2(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput))); } else { - return DummyCallerV1(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManager.OpChainConfig[]))); + OPContractsManager(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManager.OpChainConfig[]))); } } } -/// @title DummyCallerV2 -/// @notice This contract is used to mimic the contract that is used as the source of the delegatecall to the OPCM v2. -/// Uses OPContractsManagerV2.UpgradeInput type for the upgrade input. - -contract DummyCallerV2 { - address internal _opcmAddr; - - function upgrade(OPContractsManagerV2.UpgradeInput memory _upgradeInput) external returns (bool, bytes memory) { - bytes memory data = abi.encodeCall(OPContractsManagerV2.upgrade, _upgradeInput); - (bool success, bytes memory result) = _opcmAddr.delegatecall(data); - return (success, result); - } -} -/// @notice This contract is used to mimic the contract that is used as the source of the delegatecall to the OPCM v1. -/// Uses OPContractsManager.OpChainConfig[] type for the upgrade input. - -contract DummyCallerV1 { - address internal _opcmAddr; - - function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs) external returns (bool, bytes memory) { - bytes memory data = abi.encodeCall(OPContractsManager.upgrade, _opChainConfigs); - (bool success, bytes memory result) = _opcmAddr.delegatecall(data); - return (success, result); - } -} diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol index 8cc0cb13123d2..c99c251325124 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol @@ -7,6 +7,7 @@ import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2. import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; contract UpgradeSuperchainConfig is Script { struct Input { @@ -31,14 +32,16 @@ contract UpgradeSuperchainConfig is Script { // 2/2 or similar. address prank = _input.prank; - bytes memory code = _getDummyCallerCode(useOPCMv2); + bytes memory code = _getDummyCallerCode(); vm.etch(prank, code); vm.store(prank, bytes32(0), bytes32(uint256(uint160(opcm)))); vm.label(prank, "DummyCaller"); - (bool success,) = _upgrade(prank, useOPCMv2, _input); - require(success, "UpgradeSuperchainConfig: upgradeSuperchainConfig failed"); + // Call into the DummyCaller. This will perform the delegatecall under the hood. + // The DummyCaller uses a fallback that reverts on failure, so no need to check success. + vm.broadcast(msg.sender); + _upgrade(prank, useOPCMv2, _input); } /// @notice Asserts that the input is valid. @@ -50,12 +53,10 @@ contract UpgradeSuperchainConfig is Script { require(address(_input.superchainConfig) != address(0), "UpgradeSuperchainConfig: superchainConfig not set"); } - /// @notice Helper function to get the proper dummy caller code based on the OPCM version. - /// @param _useOPCMv2 Whether to use OPCM v2. + /// @notice Helper function to get the dummy caller code. /// @return code The code of the dummy caller. - function _getDummyCallerCode(bool _useOPCMv2) internal view returns (bytes memory) { - if (_useOPCMv2) return vm.getDeployedCode("UpgradeSuperchainConfig.s.sol:DummyCallerV2"); - else return vm.getDeployedCode("UpgradeSuperchainConfig.s.sol:DummyCaller"); + function _getDummyCallerCode() internal view returns (bytes memory) { + return vm.getDeployedCode("DummyCaller.sol:DummyCaller"); } /// @notice Helper function to upgrade the OPCM based on the OPCM version. Performs the decoding of the upgrade @@ -63,48 +64,16 @@ contract UpgradeSuperchainConfig is Script { /// @param _prank The address of the dummy caller contract. /// @param _useOPCMv2 Whether to use OPCM v2. /// @param _input The input. - /// @return success Whether the upgrade succeeded. - /// @return result The result of the upgrade (bool, bytes memory). - function _upgrade(address _prank, bool _useOPCMv2, Input memory _input) internal returns (bool, bytes memory) { - // Call into the DummyCaller to perform the delegatecall - vm.broadcast(msg.sender); + function _upgrade(address _prank, bool _useOPCMv2, Input memory _input) internal { if (_useOPCMv2) { - return DummyCallerV2(_prank).upgradeSuperchain( + IOPContractsManagerV2(_prank).upgradeSuperchain( IOPContractsManagerV2.SuperchainUpgradeInput({ superchainConfig: _input.superchainConfig, extraInstructions: _input.extraInstructions }) ); } else { - return DummyCaller(_prank).upgradeSuperchainConfig(_input.superchainConfig); + IOPContractsManager(_prank).upgradeSuperchainConfig(_input.superchainConfig); } } } - -/// @title DummyCaller -/// @notice This contract is used to mimic the contract that is used as the source of the delegatecall to the OPCM. -contract DummyCaller { - address internal _opcmAddr; - - function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig) external returns (bool, bytes memory) { - bytes memory data = abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (_superchainConfig)); - (bool success, bytes memory result) = _opcmAddr.delegatecall(data); - return (success, result); - } -} - -/// @title DummyCallerV2 -/// @notice This contract is used to mimic the contract that is used as the source of the delegatecall to the OPCM v2. -/// Uses IOPContractsManagerV2.SuperchainUpgradeInput type for the upgrade input. -contract DummyCallerV2 { - address internal _opcmAddr; - - function upgradeSuperchain(IOPContractsManagerV2.SuperchainUpgradeInput memory _superchainUpgradeInput) - external - returns (bool, bytes memory) - { - bytes memory data = abi.encodeCall(IOPContractsManagerV2.upgradeSuperchain, (_superchainUpgradeInput)); - (bool success, bytes memory result) = _opcmAddr.delegatecall(data); - return (success, result); - } -} diff --git a/packages/contracts-bedrock/scripts/libraries/DummyCaller.sol b/packages/contracts-bedrock/scripts/libraries/DummyCaller.sol new file mode 100644 index 0000000000000..cc98d050b728a --- /dev/null +++ b/packages/contracts-bedrock/scripts/libraries/DummyCaller.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title DummyCaller +/// @notice Generic delegatecall forwarder. Reads target from storage slot 0, +/// forwards calldata via delegatecall, reverts on failure, returns on success. +/// @dev This contract is used to mimic the contract that is used as the source of the +/// delegatecall to the OPCM. In practice this will be the governance 2/2 or similar. +/// The target address must be stored in storage slot 0 before calling any function. +contract DummyCaller { + address internal _opcmAddr; + + fallback() external { + address target = _opcmAddr; + assembly { + calldatacopy(0, 0, calldatasize()) + let result := delegatecall(gas(), target, 0, calldatasize(), 0, 0) + returndatacopy(0, 0, returndatasize()) + switch result + case 0 { revert(0, returndatasize()) } + default { return(0, returndatasize()) } + } + } +} From d761db5e912d7aecfa61660b12f14c4673aeea42 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:27:02 +0000 Subject: [PATCH 2/3] fix: remove unused DummyCaller imports Co-Authored-By: Kelvin Fichter --- packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol | 1 - packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol | 1 - packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol | 1 - .../scripts/deploy/UpgradeSuperchainConfig.s.sol | 1 - 4 files changed, 4 deletions(-) diff --git a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol index 371a60d988df8..2a4cb06896c08 100644 --- a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol @@ -6,7 +6,6 @@ import { Script } from "forge-std/Script.sol"; // Scripts import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; -import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; // Interfaces import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; diff --git a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol index 48ac77d541634..827d464e925fb 100644 --- a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol @@ -6,7 +6,6 @@ import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { IOPContractsManagerInteropMigrator, IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { Duration, Proposal, Hash } from "src/dispute/lib/Types.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; -import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol index b0283b82807e6..9af3f7f6997e8 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol @@ -6,7 +6,6 @@ import { OPContractsManager } from "src/L1/OPContractsManager.sol"; import { OPContractsManagerV2 } from "src/L1/opcm/OPContractsManagerV2.sol"; import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; -import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; contract UpgradeOPChainInput is BaseDeployIO { address internal _prank; diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol index c99c251325124..85262732b839e 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol @@ -7,7 +7,6 @@ import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2. import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; -import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; contract UpgradeSuperchainConfig is Script { struct Input { From 84fafadc7fc9e3dfb68df6d2238d13094785d2e0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:53:46 +0000 Subject: [PATCH 3/3] fix: use low-level calls and runtimeCode for DummyCaller - Use type(DummyCaller).runtimeCode instead of creationCode for vm.etch() - Use low-level calls in _upgrade() to avoid return type mismatches - Get upgradeInput before vm.broadcast() to avoid staticcall errors Co-Authored-By: Kelvin Fichter --- .../scripts/deploy/AddGameType.s.sol | 3 ++- .../scripts/deploy/InteropMigration.s.sol | 3 ++- .../scripts/deploy/UpgradeOPChain.s.sol | 21 ++++++++++++++----- .../deploy/UpgradeSuperchainConfig.s.sol | 13 ++++++++---- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol index 2a4cb06896c08..42bcf189fbf59 100644 --- a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol @@ -6,6 +6,7 @@ import { Script } from "forge-std/Script.sol"; // Scripts import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; // Interfaces import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; @@ -61,7 +62,7 @@ contract AddGameType is Script { // 2/2 or similar. address prank = _agi.prank; - bytes memory code = vm.getDeployedCode("DummyCaller.sol:DummyCaller"); + bytes memory code = type(DummyCaller).runtimeCode; vm.etch(prank, code); vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(_agi.opcmImpl))))); vm.label(prank, "DummyCaller"); diff --git a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol index 827d464e925fb..47f9a0e37cfc5 100644 --- a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol @@ -6,6 +6,7 @@ import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { IOPContractsManagerInteropMigrator, IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { Duration, Proposal, Hash } from "src/dispute/lib/Types.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; @@ -194,7 +195,7 @@ contract InteropMigration is Script { // as the source of the delegatecall to the OPCM. In practice this will be the governance // 2/2 or similar. address prank = _imi.prank(); - bytes memory code = vm.getDeployedCode("DummyCaller.sol:DummyCaller"); + bytes memory code = type(DummyCaller).runtimeCode; vm.etch(prank, code); vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(opcm))))); vm.label(prank, "DummyCaller"); diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol index 9af3f7f6997e8..df0b2799f5f7f 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol @@ -6,6 +6,7 @@ import { OPContractsManager } from "src/L1/OPContractsManager.sol"; import { OPContractsManagerV2 } from "src/L1/opcm/OPContractsManagerV2.sol"; import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; contract UpgradeOPChainInput is BaseDeployIO { address internal _prank; @@ -85,16 +86,19 @@ contract UpgradeOPChain is Script { vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(opcm))))); vm.label(prank, "DummyCaller"); + // Get the upgrade input before broadcasting + bytes memory upgradeInput = _uoci.upgradeInput(); + // Call into the DummyCaller. This will perform the delegatecall under the hood. // The DummyCaller uses a fallback that reverts on failure, so no need to check success. vm.broadcast(msg.sender); - _upgrade(prank, useOPCMv2, _uoci.upgradeInput()); + _upgrade(prank, useOPCMv2, upgradeInput); } /// @notice Helper function to get the dummy caller code. /// @return code The code of the dummy caller. - function _getDummyCallerCode() internal view returns (bytes memory) { - return vm.getDeployedCode("DummyCaller.sol:DummyCaller"); + function _getDummyCallerCode() internal pure returns (bytes memory) { + return type(DummyCaller).runtimeCode; } /// @notice Helper function to upgrade the OPCM based on the OPCM version. Performs the decoding of the upgrade @@ -103,10 +107,17 @@ contract UpgradeOPChain is Script { /// @param _useOPCMv2 Whether to use OPCM v2. /// @param _upgradeInput The upgrade input. function _upgrade(address _prank, bool _useOPCMv2, bytes memory _upgradeInput) internal { + bytes memory data; if (_useOPCMv2) { - OPContractsManagerV2(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput))); + data = abi.encodeCall( + OPContractsManagerV2.upgrade, abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput)) + ); } else { - OPContractsManager(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManager.OpChainConfig[]))); + data = abi.encodeCall( + OPContractsManager.upgrade, abi.decode(_upgradeInput, (OPContractsManager.OpChainConfig[])) + ); } + (bool success,) = _prank.call(data); + require(success, "UpgradeOPChain: upgrade failed"); } } diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol index 85262732b839e..b8bdb483a957e 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol @@ -7,6 +7,7 @@ import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2. import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; contract UpgradeSuperchainConfig is Script { struct Input { @@ -54,8 +55,8 @@ contract UpgradeSuperchainConfig is Script { /// @notice Helper function to get the dummy caller code. /// @return code The code of the dummy caller. - function _getDummyCallerCode() internal view returns (bytes memory) { - return vm.getDeployedCode("DummyCaller.sol:DummyCaller"); + function _getDummyCallerCode() internal pure returns (bytes memory) { + return type(DummyCaller).runtimeCode; } /// @notice Helper function to upgrade the OPCM based on the OPCM version. Performs the decoding of the upgrade @@ -64,15 +65,19 @@ contract UpgradeSuperchainConfig is Script { /// @param _useOPCMv2 Whether to use OPCM v2. /// @param _input The input. function _upgrade(address _prank, bool _useOPCMv2, Input memory _input) internal { + bytes memory data; if (_useOPCMv2) { - IOPContractsManagerV2(_prank).upgradeSuperchain( + data = abi.encodeCall( + IOPContractsManagerV2.upgradeSuperchain, IOPContractsManagerV2.SuperchainUpgradeInput({ superchainConfig: _input.superchainConfig, extraInstructions: _input.extraInstructions }) ); } else { - IOPContractsManager(_prank).upgradeSuperchainConfig(_input.superchainConfig); + data = abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, _input.superchainConfig); } + (bool success,) = _prank.call(data); + require(success, "UpgradeSuperchainConfig: upgrade failed"); } }