Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 12 additions & 4 deletions op-chain-ops/script/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,10 +354,18 @@ func (h *Host) Call(from common.Address, to common.Address, input []byte, gas ui

defer func() {
if r := recover(); r != nil {
// Cast to a string to check the error message. If it's not a string it's
// an unexpected panic and we should re-raise it.
rStr, ok := r.(string)
if !ok || !strings.Contains(strings.ToLower(rStr), "revision id 1") {
// Extract the panic message as a string. op-geth's journal.go panics with
// fmt.Errorf (an error type), so we must handle both string and error.
var rStr string
switch v := r.(type) {
case string:
rStr = v
case error:
rStr = v.Error()
default:
panic(r)
}
if !strings.Contains(strings.ToLower(rStr), "revision id") {
fmt.Println("panic", rStr)
panic(r)
}
Expand Down
50 changes: 40 additions & 10 deletions op-deployer/pkg/deployer/standard/standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,15 @@ func L1VersionsFor(chainID uint64) (validation.Versions, error) {
func GuardianAddressFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.Address(validation.StandardConfigRolesMainnet.Guardian), nil
// Celo Mainnet
return common.HexToAddress("0x6E226fa22e5F19363d231D3FA048aaBa73CC1f47"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesMainnet.Guardian), nil
case 11155111:
return common.Address(validation.StandardConfigRolesSepolia.Guardian), nil
// Celo Mainnet
return common.HexToAddress("0x5e60d897Cd62588291656b54655e98ee73f0aabF"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesSepolia.Guardian), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
Expand All @@ -76,9 +82,15 @@ func GuardianAddressFor(chainID uint64) (common.Address, error) {
func ChallengerAddressFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.Address(validation.StandardConfigRolesMainnet.Challenger), nil
// Celo Mainnet
return common.HexToAddress("0x6b145ebf66602ec524b196426b46631259689583"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesMainnet.Challenger), nil
case 11155111:
return common.Address(validation.StandardConfigRolesSepolia.Challenger), nil
// Celo Mainnet
return common.HexToAddress("0xC813b28614BD4CFA3d5Fdf153df41B273AB9D497"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesSepolia.Challenger), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
Expand Down Expand Up @@ -121,9 +133,15 @@ func OPCMImplAddressFor(chainID uint64, tag string) (common.Address, error) {
func SuperchainProxyAdminAddrFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.HexToAddress("0x543bA4AADBAb8f9025686Bd03993043599c6fB04"), nil
// Celo Mainnet
return common.HexToAddress("0x783A434532Ee94667979213af1711505E8bFE374"), nil
// Superchain
// return common.HexToAddress("0x543bA4AADBAb8f9025686Bd03993043599c6fB04"), nil
case 11155111:
return common.HexToAddress("0x189aBAAaa82DfC015A588A7dbaD6F13b1D3485Bc"), nil
// Celo Mainnet
return common.HexToAddress("0xf7d7a3d3bb8abb6829249b3d3ad3d525d052027e"), nil
// Superchain
// return common.HexToAddress("0x189aBAAaa82DfC015A588A7dbaD6F13b1D3485Bc"), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
Expand All @@ -132,9 +150,15 @@ func SuperchainProxyAdminAddrFor(chainID uint64) (common.Address, error) {
func L1ProxyAdminOwner(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.Address(validation.StandardConfigRolesMainnet.L1ProxyAdminOwner), nil
// Celo Mainnet
return common.HexToAddress("0x4092A77bAF58fef0309452cEaCb09221e556E112"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesMainnet.L1ProxyAdminOwner), nil
case 11155111:
return common.Address(validation.StandardConfigRolesSepolia.L1ProxyAdminOwner), nil
// Celo Mainnet
return common.HexToAddress("0x5e60d897Cd62588291656b54655e98ee73f0aabF"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesSepolia.L1ProxyAdminOwner), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
Expand All @@ -154,9 +178,15 @@ func L2ProxyAdminOwner(chainID uint64) (common.Address, error) {
func ProtocolVersionsOwner(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.Address(validation.StandardConfigRolesMainnet.ProtocolVersionsOwner), nil
// Celo Mainnet
return common.HexToAddress("0x4092A77bAF58fef0309452cEaCb09221e556E112"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesMainnet.ProtocolVersionsOwner), nil
case 11155111:
return common.Address(validation.StandardConfigRolesSepolia.ProtocolVersionsOwner), nil
// Celo Mainnet
return common.HexToAddress("0x5e60d897Cd62588291656b54655e98ee73f0aabF"), nil
// Superchain
// return common.Address(validation.StandardConfigRolesSepolia.ProtocolVersionsOwner), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
Expand Down
1 change: 1 addition & 0 deletions op-deployer/pkg/deployer/upgrade/v2_0_0/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type UpgradeOPChainInput struct {
Prank common.Address `json:"prank"`
Opcm common.Address `json:"opcm"`
EncodedChainConfigs []OPChainConfig `evm:"-" json:"chainConfigs"`
UpgradeSuperchainConfig bool `json:"upgradeSuperchainConfig"`
}

type OPChainConfig struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ interface IOPContractsManagerUpgrader {

function __constructor__(IOPContractsManagerContractsContainer _contractsContainer) external;

function upgrade(IOPContractsManager.OpChainConfig[] memory _opChainConfigs) external;
function upgrade(IOPContractsManager.OpChainConfig[] memory _opChainConfigs, bool _upgradeSuperchainConfig) external;

function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig, IProxyAdmin _superchainProxyAdmin) external;

Expand Down Expand Up @@ -339,7 +339,8 @@ interface IOPContractsManager {

/// @notice Upgrades the implementation of all proxies in the specified chains
/// @param _opChainConfigs The chains to upgrade
function upgrade(OpChainConfig[] memory _opChainConfigs) external;
/// @param _upgradeSuperchainConfig Flag to optionally upgrade superchain config
function upgrade(OpChainConfig[] memory _opChainConfigs, bool _upgradeSuperchainConfig) external;

/// @notice Upgrades the SuperchainConfig contract.
/// @param _superchainConfig The SuperchainConfig contract to upgrade.
Expand Down
17 changes: 14 additions & 3 deletions packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ contract UpgradeOPChainInput is BaseDeployIO {
address internal _prank;
OPContractsManager internal _opcm;
bytes _opChainConfigs;
bool _upgradeSuperchainConfig;

// Setter for OPContractsManager type
function set(bytes4 _sel, address _value) public {
Expand All @@ -26,6 +27,11 @@ contract UpgradeOPChainInput is BaseDeployIO {
else revert("UpgradeOPCMInput: unknown selector");
}

function set(bytes4 _sel, bool _value) public {
if (_sel == this.upgradeSuperchainConfig.selector) _upgradeSuperchainConfig = _value;
else revert("UpgradeOPCMInput: unknown selector");
}

function prank() public view returns (address) {
require(address(_prank) != address(0), "UpgradeOPCMInput: prank not set");
return _prank;
Expand All @@ -40,13 +46,18 @@ contract UpgradeOPChainInput is BaseDeployIO {
require(_opChainConfigs.length > 0, "UpgradeOPCMInput: not set");
return _opChainConfigs;
}

function upgradeSuperchainConfig() public view returns (bool) {
return _upgradeSuperchainConfig;
}
}

contract UpgradeOPChain is Script {
function run(UpgradeOPChainInput _uoci) external {
OPContractsManager opcm = _uoci.opcm();
OPContractsManager.OpChainConfig[] memory opChainConfigs =
abi.decode(_uoci.opChainConfigs(), (OPContractsManager.OpChainConfig[]));
bool upgradeSuperchainConfig_ = _uoci.upgradeSuperchainConfig();

// 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
Expand All @@ -60,16 +71,16 @@ contract UpgradeOPChain is Script {
// Call into the DummyCaller. This will perform the delegatecall under the hood and
// return the result.
vm.broadcast(msg.sender);
(bool success,) = DummyCaller(prank).upgrade(opChainConfigs);
(bool success,) = DummyCaller(prank).upgrade(opChainConfigs, upgradeSuperchainConfig_);
require(success, "UpgradeChain: upgrade failed");
}
}

contract DummyCaller {
address internal _opcmAddr;

function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs) external returns (bool, bytes memory) {
bytes memory data = abi.encodeCall(DummyCaller.upgrade, _opChainConfigs);
function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs, bool _upgradeSuperchainConfig) external returns (bool, bytes memory) {
bytes memory data = abi.encodeCall(DummyCaller.upgrade, (_opChainConfigs, _upgradeSuperchainConfig));
(bool success, bytes memory result) = _opcmAddr.delegatecall(data);
return (success, result);
}
Expand Down
27 changes: 20 additions & 7 deletions packages/contracts-bedrock/src/L1/OPContractsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisput
import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGame.sol";
import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IHasSuperchainConfig } from "interfaces/L1/IHasSuperchainConfig.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol";
import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol";
Expand Down Expand Up @@ -732,10 +733,11 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase {

/// @notice Upgrades a set of chains to the latest implementation contracts
/// @param _opChainConfigs Array of OpChain structs, one per chain to upgrade
/// @param _upgradeSuperchainConfig Flag to indicate if superchainConfig should be upgraded
/// @dev This function is intended to be DELEGATECALLed by an address that is the common owner of every chain in
/// `_opChainConfigs`'s ProxyAdmin.
/// @dev This function requires that each chain's superchainConfig is already upgraded.
function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs) external virtual {
function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs, bool _upgradeSuperchainConfig) external virtual {
// Grab the implementations.
OPContractsManager.Implementations memory impls = getImplementations();

Expand All @@ -745,11 +747,17 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase {
uint256 l2ChainId = _opChainConfigs[i].systemConfigProxy.l2ChainId();

// Grab the SuperchainConfig.
ISuperchainConfig superchainConfig = _opChainConfigs[i].systemConfigProxy.superchainConfig();
ISuperchainConfig celoSuperchainConfig = _opChainConfigs[i].systemConfigProxy.superchainConfig();
ISuperchainConfig superchainConfig = IHasSuperchainConfig(address(celoSuperchainConfig)).superchainConfig();

// SuperchainConfig should be in older version than impl on Celo L1.
if (!SemverComp.lt(superchainConfig.version(), ISuperchainConfig(impls.superchainConfigImpl).version())) {
revert OPContractsManagerUpgrader_SuperchainConfigMismatch();
{
if (!SemverComp.lt(superchainConfig.version(), ISuperchainConfig(impls.superchainConfigImpl).version())) {
revert OPContractsManagerUpgrader_SuperchainConfigMismatch();
} else if (_upgradeSuperchainConfig) {
Comment on lines +755 to +757

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Upgrade shared SuperchainConfig only once per batch

This loop checks that superchainConfig.version() < target for every chain, then conditionally upgrades SuperchainConfig inside the same loop. If multiple entries reference the same underlying SuperchainConfig and _upgradeSuperchainConfig is enabled, the first iteration upgrades it and the next iteration fails this < target check, reverting the whole batched chain upgrade.

Useful? React with 👍 / 👎.

Comment on lines +755 to +757

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid re-checking post-upgrade superchain version per chain

This version gate runs on every iteration and requires superchainConfig.version() < target. If _upgradeSuperchainConfig is enabled, the first chain upgrades the shared superchain config, then the next chain sees an equal version and immediately reverts with OPContractsManagerUpgrader_SuperchainConfigMismatch. Because the superchain config is shared across chains, this breaks multi-chain upgrades whenever _opChainConfigs has more than one entry.

Useful? React with 👍 / 👎.

// Celo: some chains (like Celo Mainnet) follow external superchain config that is not desired to be upgraded
__upgradeSuperchainConfig(superchainConfig, _opChainConfigs[i].proxyAdmin);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass superchain ProxyAdmin when upgrading superchain config

When _upgradeSuperchainConfig is true, this call passes each chain’s proxyAdmin into __upgradeSuperchainConfig, but that function upgrades the shared SuperchainConfig proxy and expects the Superchain proxy admin. In deployments where chain ProxyAdmins differ from the Superchain ProxyAdmin, the upgrade path will revert and abort the entire upgrade(...) call.

Useful? React with 👍 / 👎.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass the shared superchain ProxyAdmin for in-loop upgrades

When _upgradeSuperchainConfig is true, the loop upgrades superchainConfig using _opChainConfigs[i].proxyAdmin, but that field is the per-chain ProxyAdmin, not necessarily the shared SuperchainConfig ProxyAdmin. In deployments where those admins differ (the normal topology with one shared superchain config and per-chain admins), this path will revert during upgradeTo, so the new upgrade(..., true) mode cannot be used even for a valid chain config.

Useful? React with 👍 / 👎.

}
}

// Do the chain upgrade.
Expand Down Expand Up @@ -898,12 +906,16 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase {
}
}

function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig, IProxyAdmin _superchainProxyAdmin) external {
__upgradeSuperchainConfig(_superchainConfig, _superchainProxyAdmin);
}

/// @notice Upgrades the SuperchainConfig contract.
/// @param _superchainConfig The SuperchainConfig contract to upgrade.
/// @param _superchainProxyAdmin The ProxyAdmin contract to use for the upgrade.
/// @dev This function is intended to be DELEGATECALLed by the superchainConfig's ProxyAdminOwner.
/// @dev This function will revert if the SuperchainConfig is already at or above the target version.
function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig, IProxyAdmin _superchainProxyAdmin) external {
function __upgradeSuperchainConfig(ISuperchainConfig _superchainConfig, IProxyAdmin _superchainProxyAdmin) internal {
// Only upgrade the superchainConfig if the current version is less than the target version.
if (
SemverComp.gte(
Expand Down Expand Up @@ -2031,13 +2043,14 @@ contract OPContractsManager is ISemver {

/// @notice Upgrades a set of chains to the latest implementation contracts
/// @param _opChainConfigs Array of OpChain structs, one per chain to upgrade
/// @param _upgradeSuperchainConfig Flag to indicate if superchainConfig should be upgraded
/// @dev This function is intended to be DELEGATECALLed by an address that is the common owner of every chain in
/// `_opChainConfigs`'s ProxyAdmin.
/// @dev This function requires that each chain's superchainConfig is already upgraded.
function upgrade(OpChainConfig[] memory _opChainConfigs) external virtual {
function upgrade(OpChainConfig[] memory _opChainConfigs, bool _upgradeSuperchainConfig) external virtual {
if (address(this) == address(thisOPCM)) revert OnlyDelegatecall();

bytes memory data = abi.encodeCall(OPContractsManagerUpgrader.upgrade, (_opChainConfigs));
bytes memory data = abi.encodeCall(OPContractsManagerUpgrader.upgrade, (_opChainConfigs, _upgradeSuperchainConfig));
_performDelegateCall(address(opcmUpgrader), data);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.so
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IHasSuperchainConfig } from "interfaces/L1/IHasSuperchainConfig.sol";
import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol";
import { IL1StandardBridge } from "interfaces/L1/IL1StandardBridge.sol";
import { IL1ERC721Bridge } from "interfaces/L1/IL1ERC721Bridge.sol";
Expand Down Expand Up @@ -232,6 +233,10 @@ contract OPContractsManagerStandardValidator is ISemver {
return _errors;
}

function celoSuperchainConfig(address _celoSuperchainConfig) internal view returns (ISuperchainConfig) {
return IHasSuperchainConfig(_celoSuperchainConfig).superchainConfig();
}

/// @notice Asserts that the SystemConfig contract is valid.
function assertValidSystemConfig(
string memory _errors,
Expand Down Expand Up @@ -261,13 +266,31 @@ contract OPContractsManagerStandardValidator is ISemver {
_errors = internalRequire(_sysCfg.operatorFeeScalar() == 0, "SYSCON-110", _errors);
_errors = internalRequire(_sysCfg.operatorFeeConstant() == 0, "SYSCON-120", _errors);
_errors = internalRequire(getProxyAdmin(address(_sysCfg)) == _admin, "SYSCON-130", _errors);
_errors = internalRequire(_sysCfg.superchainConfig() == superchainConfig, "SYSCON-140", _errors);
_errors = internalRequire(celoSuperchainConfig(address(_sysCfg.superchainConfig())) == superchainConfig, "SYSCON-140", _errors);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fall back when SystemConfig already points to SuperchainConfig

This now assumes _sysCfg.superchainConfig() is a Celo wrapper implementing IHasSuperchainConfig, then dereferences one level deeper. On standard deployments where SystemConfig.superchainConfig() already returns the actual SuperchainConfig, that extra call is made against a contract that does not expose superchainConfig(), causing validate(...) to revert instead of reporting validation errors.

Useful? React with 👍 / 👎.


// CGT prevents Lockbox
if (_sysCfg.isCustomGasToken()) {
_errors = internalRequire(!_sysCfg.isFeatureEnabled(Features.ETH_LOCKBOX), "SYSCON-150", _errors);
}

// Celo extra validation: custom gas token
(address address_, uint8 decimals_) = _sysCfg.gasPayingToken();
address expected_;
string memory name_;
if (address(_sysCfg) == address(0x760a5F022C9940f4A074e0030be682F560d29818)) {
// sepolia
expected_ = address(0x3C7011fD5e6Aed460cAa4985cF8d8Caba435b092);
name_ = "Celo";
} else if (address(_sysCfg) == address(0x89E31965D844a309231B1f17759Ccaf1b7c09861)) {
// mainnet
expected_ = address(0x057898f3C43F129a17517B9056D23851F124b19f);
name_ = "Celo native asset";
}
_errors = internalRequire(address_ == expected_, "SYSCON-CEL-10", _errors);
_errors = internalRequire(decimals_ == 18, "SYSCON-CEL-20", _errors);
_errors = internalRequire(LibString.eq(_sysCfg.gasPayingTokenName(), name_) , "SYSCON-CEL-30", _errors);
_errors = internalRequire(LibString.eq(_sysCfg.gasPayingTokenSymbol(), "CELO") , "SYSCON-CEL-40", _errors);

return _errors;
}

Expand Down Expand Up @@ -421,6 +444,16 @@ contract OPContractsManagerStandardValidator is ISemver {
_errors = internalRequire(address(_portal.systemConfig()) == address(_sysCfg), "PORTAL-40", _errors);
_errors = internalRequire(_portal.l2Sender() == Constants.DEFAULT_L2_SENDER, "PORTAL-80", _errors);
_errors = internalRequire(getProxyAdmin(address(_portal)) == _admin, "PORTAL-90", _errors);

// Celo extra validation: celo superchain config vs external superchain config
address celoSuperchainConfig_ = address(_portal.superchainConfig());
_errors = internalRequire(
_portal.guardian() != superchainConfig.guardian(), "PORTAL-CEL-10", _errors
); // True only for Celo Mainnet
_errors = internalRequire(
_portal.guardian() == ISuperchainConfig(celoSuperchainConfig_).guardian(), "PORTAL-CEL-20", _errors
); // True for Celo Mainnet & Celo Testnets

return _errors;
}

Expand Down Expand Up @@ -451,7 +484,7 @@ contract OPContractsManagerStandardValidator is ISemver {
_errors = internalRequire(_lockbox.systemConfig() == _sysCfg, "LOCKBOX-40", _errors);
_errors = internalRequire(_lockbox.authorizedPortals(_portal), "LOCKBOX-50", _errors);
// Lockbox is not compatible with CGT
_errors = internalRequire(!_sysCfg.isCustomGasToken(), "LOCKBOX-60", _errors);
_errors = internalRequire(!_sysCfg.isCustomGasToken(), "LOCKBOX-CEL-10", _errors);
return _errors;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/test/L1/OPContractsManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ contract OPContractsManager_Upgrade_Harness is CommonTest {

// Execute the chain upgrade.
DelegateCaller(_delegateCaller).dcForward(
address(_opcm), abi.encodeCall(IOPContractsManager.upgrade, (opChainConfigs))
address(_opcm), abi.encodeCall(IOPContractsManager.upgrade, (opChainConfigs, false))
);

// Return early if a revert was expected. Otherwise we'll get errors below.
Expand Down Expand Up @@ -1343,7 +1343,7 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
function test_upgrade_notDelegateCalled_reverts() public {
vm.prank(upgrader);
vm.expectRevert(IOPContractsManager.OnlyDelegatecall.selector);
opcm.upgrade(opChainConfigs);
opcm.upgrade(opChainConfigs, false);
}

function test_upgrade_notProxyAdminOwner_reverts() public {
Expand Down
Loading