Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 8 additions & 24 deletions packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 = type(DummyCaller).runtimeCode;
vm.etch(prank, code);
vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(_agi.opcmImpl)))));
vm.label(prank, "DummyCaller");
Expand All @@ -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 });
}
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 = type(DummyCaller).runtimeCode;
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()));
Expand All @@ -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);
}
}
70 changes: 22 additions & 48 deletions packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -80,70 +81,43 @@ 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");
// 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, 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 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
/// input and the delegatecall to the OPCM.
/// @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 {
bytes memory data;
if (_useOPCMv2) {
return DummyCallerV2(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput)));
data = abi.encodeCall(
OPContractsManagerV2.upgrade, abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput))
);
} else {
return DummyCallerV1(_prank).upgrade(abi.decode(_upgradeInput, (OPContractsManager.OpChainConfig[])));
data = abi.encodeCall(
OPContractsManager.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);
(bool success,) = _prank.call(data);
require(success, "UpgradeOPChain: upgrade failed");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand All @@ -50,61 +53,31 @@ 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 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
/// input and the delegatecall to the OPCM.
/// @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 {
bytes memory data;
if (_useOPCMv2) {
return DummyCallerV2(_prank).upgradeSuperchain(
data = abi.encodeCall(
IOPContractsManagerV2.upgradeSuperchain,
IOPContractsManagerV2.SuperchainUpgradeInput({
superchainConfig: _input.superchainConfig,
extraInstructions: _input.extraInstructions
})
);
} else {
return DummyCaller(_prank).upgradeSuperchainConfig(_input.superchainConfig);
data = abi.encodeCall(IOPContractsManager.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);
(bool success,) = _prank.call(data);
require(success, "UpgradeSuperchainConfig: upgrade failed");
}
}
24 changes: 24 additions & 0 deletions packages/contracts-bedrock/scripts/libraries/DummyCaller.sol
Original file line number Diff line number Diff line change
@@ -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()) }
}
}
}