Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3b4f29b
Upgrade 18 Template
Wazabie Dec 3, 2025
8cc318c
fix: remove references to superchainconfig
ZakAyesh Dec 3, 2025
07ee22a
Merge branch 'main' into u18-template
Wazabie Dec 3, 2025
9ae22a3
Update env and config of example task
Wazabie Dec 3, 2025
c73c436
Merge branch 'u18-template' of https://github.com/ethereum-optimism/s…
Wazabie Dec 3, 2025
e880551
Include the superchainConfig upgrade task
Wazabie Dec 3, 2025
4a3ca5e
Merge branch 'main' into u18-template
Wazabie Dec 10, 2025
6f3b59f
Update templates for v600 breaking changes
Wazabie Dec 11, 2025
a3107d9
Update example tasks to run on betanet
Wazabie Dec 11, 2025
c9cd5d8
Update references
Wazabie Dec 19, 2025
193f7c9
Chore Update
Wazabie Dec 19, 2025
638e110
Chore updates
Wazabie Dec 19, 2025
af94fb4
Remove unused superchainConfig
Wazabie Dec 19, 2025
b71c1f4
formatting fixes
Wazabie Dec 19, 2025
a70b776
Merge branch 'main' into u18-template
Wazabie Dec 19, 2025
b84f9be
format fix
Wazabie Dec 19, 2025
d39eaa8
Merge branch 'u18-template' of https://github.com/ethereum-optimism/s…
Wazabie Dec 19, 2025
7e2173e
Update OPCMUpgradeV600.sol
Wazabie Dec 19, 2025
54cfb0d
Update Regression.t.sol
Wazabie Dec 19, 2025
7f9cc61
Revert "Update Regression.t.sol"
Wazabie Dec 19, 2025
2ed9b79
Update config.toml
Wazabie Dec 19, 2025
fd932d0
Update to use sepolia for example task
Wazabie Dec 19, 2025
462fb98
Update Regression.t.sol
Wazabie Dec 19, 2025
4de9247
Update config.toml
Wazabie Dec 19, 2025
a89d0eb
Update comments
Wazabie Dec 19, 2025
ef3b6fc
fix: address matt's code review
ZakAyesh Dec 22, 2025
9a39ed1
Update the overrides checks
Wazabie Dec 22, 2025
8d55b2f
Update OPCMUpgradeV600.sol
Wazabie Dec 22, 2025
7147ded
Update OPCMUpgradeV600.sol
Wazabie Dec 22, 2025
48c9651
Update OPCMUpgradeV600.sol
Wazabie Dec 22, 2025
17d5f82
Update OPCMUpgradeV600.sol
Wazabie Dec 22, 2025
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
84 changes: 84 additions & 0 deletions src/template/OPCMUpgradeSuperchainConfigV600.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {
IOPContractsManager,
ISuperchainConfig
} from "@eth-optimism-bedrock/interfaces/L1/IOPContractsManager.sol";
import {EIP1967Helper} from "@eth-optimism-bedrock/test/mocks/EIP1967Helper.sol";
import {VmSafe} from "forge-std/Vm.sol";
import {stdToml} from "forge-std/StdToml.sol";
import {LibString} from "solady/utils/LibString.sol";

import {OPCMTaskBase} from "src/tasks/types/OPCMTaskBase.sol";
import {Action} from "src/libraries/MultisigTypes.sol";

/// @notice OPCM SuperchainConfig V6.0.0 upgrade template.
/// @dev This template is used to upgrade the SuperchainConfig contract from V5.0.0 to V6.0.0.
/// Supports: op-contracts/v5.0.0
contract OPCMUpgradeSuperchainConfigV600 is OPCMTaskBase {
using stdToml for string;
using LibString for string;

ISuperchainConfig public SUPERCHAIN_CONFIG;

/// @notice Returns the storage write permissions required for this task. This is an array of
/// contract names that are expected to be written to during the execution of the task.
function _taskStorageWrites() internal pure virtual override returns (string[] memory) {
string[] memory storageWrites = new string[](1);
storageWrites[0] = "SuperchainConfig";
return storageWrites;
}

/// @notice Returns an array of strings that refer to contract names in the address registry.
/// Contracts with these names are expected to have their balance changes during the task.
/// By default returns an empty array. Override this function if your task expects balance changes.
function _taskBalanceChanges() internal view virtual override returns (string[] memory) {}

/// @notice Sets up the template with implementation configurations from a TOML file.
/// State overrides are not applied yet. Keep this in mind when performing various pre-simulation assertions in this function.
function _templateSetup(string memory _taskConfigFilePath, address _rootSafe) internal override {
super._templateSetup(_taskConfigFilePath, _rootSafe);
string memory tomlContent = vm.readFile(_taskConfigFilePath);

address OPCM = tomlContent.readAddress(".addresses.OPCM");
OPCM_TARGETS.push(OPCM);
require(IOPContractsManager(OPCM).version().eq("6.0.0"), "Incorrect OPCM");
vm.label(OPCM, "OPCM");

SUPERCHAIN_CONFIG = ISuperchainConfig(tomlContent.readAddress(".addresses.SuperchainConfig"));
require(address(SUPERCHAIN_CONFIG).code.length > 0, "Incorrect SuperchainConfig - no code at address");
vm.label(address(SUPERCHAIN_CONFIG), "SuperchainConfig");
Comment thread
Wazabie marked this conversation as resolved.
Outdated
}

/// @notice Builds the actions for executing the operations.
function _build(address) internal override {
(bool success,) = OPCM_TARGETS[0].delegatecall(
abi.encodeCall(
IOPContractManagerV600.upgradeSuperchainConfig, (SUPERCHAIN_CONFIG)
)
);
require(success, "OPCMUpgradeSuperchainConfigV600: Delegatecall failed in _build.");
Comment thread
Wazabie marked this conversation as resolved.
Outdated
}
Comment thread
Wazabie marked this conversation as resolved.
Outdated

/// @notice This method performs all validations and assertions that verify the calls executed as expected.
function _validate(VmSafe.AccountAccess[] memory, Action[] memory, address) internal view override {
require(
EIP1967Helper.getImplementation(address(SUPERCHAIN_CONFIG))
== IOPContractsManager(OPCM_TARGETS[0]).implementations().superchainConfigImpl,
"OPCMUpgradeSuperchainConfigV600: Incorrect SuperchainConfig implementation after upgradeSuperchainConfig"
);
require(
SUPERCHAIN_CONFIG.version().eq("2.4.0"),
"OPCMUpgradeSuperchainConfigV600: Incorrect SuperchainConfig version after upgradeSuperchainConfig"
);
}

/// @notice Override to return a list of addresses that should not be checked for code length.
function _getCodeExceptions() internal view virtual override returns (address[] memory) {}
}

interface IOPContractManagerV600 {
function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig)
external;
}
203 changes: 203 additions & 0 deletions src/template/OPCMUpgradeV600.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {
ISystemConfig
} from "@eth-optimism-bedrock/interfaces/L1/IOPContractsManager.sol";
import {Claim} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol";
import {VmSafe} from "forge-std/Vm.sol";
import {stdToml} from "forge-std/StdToml.sol";
import {LibString} from "solady/utils/LibString.sol";

import {OPCMTaskBase} from "src/tasks/types/OPCMTaskBase.sol";
import {SuperchainAddressRegistry} from "src/SuperchainAddressRegistry.sol";
import {Action} from "src/libraries/MultisigTypes.sol";

/// @notice A template contract for configuring OPCMTaskBase templates.
/// Supports: op-contracts/v6.0.0
contract OPCMUpgradeV600 is OPCMTaskBase {
using stdToml for string;
using LibString for string;

/// @notice Struct to store inputs data for each L2 chain.
struct OPCMUpgrade {
Claim cannonPrestate;
Claim cannonKonaPrestate;
uint256 chainId;
string expectedValidationErrors;
}

/// @notice Mapping of L2 chain IDs to their respective OPCMUpgrade structs.
mapping(uint256 => OPCMUpgrade) public upgrades;

/// @notice The Standard Validator returned by OPCM
IOPContractsManagerStandardValidator public STANDARD_VALIDATOR;

/// @notice OPCM we delegatecall into (must be v6.0.0).
address public OPCM;

/// @notice Names in the SuperchainAddressRegistry that are expected to be written during this task.
function _taskStorageWrites() internal pure virtual override returns (string[] memory) {
Comment thread
Wazabie marked this conversation as resolved.
Outdated
string[] memory storageWrites = new string[](10);
Comment thread
Wazabie marked this conversation as resolved.
Outdated
storageWrites[0] = "DisputeGameFactoryProxy";
storageWrites[1] = "SystemConfigProxy";
storageWrites[2] = "OptimismPortalProxy";
storageWrites[3] = "OptimismMintableERC20FactoryProxy";
storageWrites[4] = "AddressManager";
storageWrites[5] = "L1CrossDomainMessengerProxy";
storageWrites[6] = "L1StandardBridgeProxy";
storageWrites[7] = "L1ERC721BridgeProxy";
storageWrites[8] = "ProxyAdminOwner";
storageWrites[9] = "AnchorStateRegistryProxy";
Comment thread
Wazabie marked this conversation as resolved.
Outdated
return storageWrites;
}

/// @notice Returns an array of strings that refer to contract names in the address registry.
/// Contracts with these names are expected to have their balance changes during the task.
/// By default returns an empty array. Override this function if your task expects balance changes.
function _taskBalanceChanges() internal view virtual override returns (string[] memory) {}
Comment thread
Wazabie marked this conversation as resolved.

/// @notice Sets up the template with implementation configurations from a TOML file.
function _templateSetup(string memory taskConfigFilePath, address rootSafe) internal override {
super._templateSetup(taskConfigFilePath, rootSafe);
string memory tomlContent = vm.readFile(taskConfigFilePath);


// Load upgrades from TOML
OPCMUpgrade[] memory _upgrades = abi.decode(tomlContent.parseRaw(".opcmUpgrades"), (OPCMUpgrade[]));
for (uint256 i = 0; i < _upgrades.length; i++) {
upgrades[_upgrades[i].chainId] = _upgrades[i];
Comment thread
mds1 marked this conversation as resolved.
}
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.

// OPCM from TOML; must be v6.0.0
OPCM = tomlContent.readAddress(".addresses.OPCM");
OPCM_TARGETS.push(OPCM);
require(IOPContractsManagerV600(OPCM).version().eq("6.0.0"), "Incorrect OPCM");
vm.label(OPCM, "OPCM");

// Fetch the validator directly from OPCM so it doesn't need to be configured in TOML
address validatorAddr = address(IOPCM(OPCM).opcmStandardValidator());
require(validatorAddr != address(0), "OPCM returned zero validator");
require(validatorAddr.code.length > 0, "Validator has no code");
STANDARD_VALIDATOR = IOPContractsManagerStandardValidator(validatorAddr);
vm.label(address(STANDARD_VALIDATOR), "OPCMStandardValidator");
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.
}

/// @notice Builds the actions for executing the operations.
function _build(address) internal override {
SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains();
IOPContractsManagerV600.OpChainConfig[] memory opChainConfigs =
new IOPContractsManagerV600.OpChainConfig[](chains.length);
Comment thread
Wazabie marked this conversation as resolved.

for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i].chainId;
require(upgrades[chainId].chainId != 0, "OPCMUpgradeV600: Config not found for chain");
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.
Comment thread
Wazabie marked this conversation as resolved.

// Optional: enforce non-zero prestates, per U18 notes
Comment thread
Wazabie marked this conversation as resolved.
Outdated
require(
Claim.unwrap(upgrades[chainId].cannonPrestate) != bytes32(0),
"OPCMUpgradeV600: cannonPrestate is zero"
);
require(
Claim.unwrap(upgrades[chainId].cannonKonaPrestate) != bytes32(0),
"OPCMUpgradeV600: cannonKonaPrestate is zero"
);
Comment thread
Wazabie marked this conversation as resolved.

opChainConfigs[i] = IOPContractsManagerV600.OpChainConfig({
systemConfigProxy: ISystemConfig(superchainAddrRegistry.getAddress("SystemConfigProxy", chainId)),
cannonPrestate: upgrades[chainId].cannonPrestate,
cannonKonaPrestate: upgrades[chainId].cannonKonaPrestate
});
}
Comment thread
Wazabie marked this conversation as resolved.

// Delegatecall the OPCM.upgrade() function (new U18 signature)
Comment thread
Wazabie marked this conversation as resolved.
Outdated
(bool ok2,) =
OPCM_TARGETS[0].delegatecall(abi.encodeWithSelector(IOPContractsManagerV600.upgrade.selector, opChainConfigs));
require(ok2, "OPCMUpgradeV600: Delegatecall failed in _build.");
Comment thread
Wazabie marked this conversation as resolved.
Outdated
}

/// @notice This method performs all validations and assertions that verify the calls executed as expected.
function _validate(VmSafe.AccountAccess[] memory, Action[] memory, address) internal view override {
SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains();
for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i].chainId;
bytes32 expCannonPrestate = Claim.unwrap(upgrades[chainId].cannonPrestate);
bytes32 expCannonKonaPrestate = Claim.unwrap(upgrades[chainId].cannonKonaPrestate);
string memory expErrors = upgrades[chainId].expectedValidationErrors;
address sysCfg = superchainAddrRegistry.getAddress("SystemConfigProxy", chainId);
address proposer = superchainAddrRegistry.getAddress("Proposer", chainId);

require(proposer != address(0), "OPCMUpgradeV600: proposer is zero");

IOPContractsManagerStandardValidator.ValidationInputDev memory input = IOPContractsManagerStandardValidator
.ValidationInputDev({
sysCfg: ISystemConfig(sysCfg),
Comment thread
Wazabie marked this conversation as resolved.
Outdated
cannonPrestate: expCannonPrestate,
cannonKonaPrestate: expCannonKonaPrestate,
l2ChainID: chainId,
proposer: proposer
});

IOPContractsManagerStandardValidator.ValidationOverrides memory overrides_ =
IOPContractsManagerStandardValidator.ValidationOverrides({
l1PAOMultisig: superchainAddrRegistry.getAddress("ProxyAdminOwner", chainId),
challenger: superchainAddrRegistry.getAddress("Challenger", chainId)
});
Comment thread
Wazabie marked this conversation as resolved.
Outdated

string memory errors =
STANDARD_VALIDATOR.validateWithOverrides({_input: input, _allowFailure: true, _overrides: overrides_});

require(errors.eq(expErrors), string.concat("Unexpected errors: ", errors, "; expected: ", expErrors));
}
}

/// @notice Override to return a list of addresses that should not be checked for code length.
function _getCodeExceptions() internal view virtual override returns (address[] memory) {}
}

/* ---------- Interfaces ---------- */
/// @notice OPCM Interface.
interface IOPContractsManagerV600 {
struct OpChainConfig {
ISystemConfig systemConfigProxy;
Claim cannonPrestate;
Claim cannonKonaPrestate;
}

function version() external view returns (string memory);

function upgrade(OpChainConfig[] memory _opChainConfigs) external;

function opcmStandardValidator() external view returns (IOPContractsManagerStandardValidator);
}

/// @notice Interface to retrieve the standard validator from OPCM.
interface IOPCM {
function opcmStandardValidator() external view returns (IOPContractsManagerStandardValidator);
}

/// @notice Validator interface for validateWithOverrides usage.
interface IOPContractsManagerStandardValidator {
struct ValidationInputDev {
ISystemConfig sysCfg;
bytes32 cannonPrestate;
bytes32 cannonKonaPrestate;
uint256 l2ChainID;
address proposer;
}

struct ValidationOverrides {
address l1PAOMultisig;
address challenger;
}

function validate(ValidationInputDev memory _input, bool _allowFailure) external view returns (string memory);

function validateWithOverrides(
ValidationInputDev memory _input,
bool _allowFailure,
ValidationOverrides memory _overrides
) external view returns (string memory);

function version() external view returns (string memory);
}
Loading