Skip to content

Commit

Permalink
feat: Add upgrade of superchain singletons
Browse files Browse the repository at this point in the history
  • Loading branch information
maurelian committed Jan 16, 2025
1 parent ee36e4e commit a943dc7
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol";
import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
import { Solarray } from "scripts/libraries/Solarray.sol";
import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol";
import { DeploySuperchainImplementations, DeploySuperchainOutput } from "scripts/deploy/DeploySuperchain.s.sol";

// See DeploySuperchain.s.sol for detailed comments on the script architecture used here.
contract DeployImplementationsInput is BaseDeployIO {
Expand Down Expand Up @@ -143,6 +144,8 @@ contract DeployImplementationsOutput is BaseDeployIO {
IOptimismMintableERC20Factory internal _optimismMintableERC20FactoryImpl;
IDisputeGameFactory internal _disputeGameFactoryImpl;
IAnchorStateRegistry internal _anchorStateRegistryImpl;
ISuperchainConfig internal _superchainConfigImpl;
IProtocolVersions internal _protocolVersionsImpl;

function set(bytes4 _sel, address _addr) public {
require(_addr != address(0), "DeployImplementationsOutput: cannot set zero address");
Expand All @@ -160,6 +163,8 @@ contract DeployImplementationsOutput is BaseDeployIO {
else if (_sel == this.optimismMintableERC20FactoryImpl.selector) _optimismMintableERC20FactoryImpl = IOptimismMintableERC20Factory(_addr);
else if (_sel == this.disputeGameFactoryImpl.selector) _disputeGameFactoryImpl = IDisputeGameFactory(_addr);
else if (_sel == this.anchorStateRegistryImpl.selector) _anchorStateRegistryImpl = IAnchorStateRegistry(_addr);
else if (_sel == this.superchainConfigImpl.selector) _superchainConfigImpl = ISuperchainConfig(_addr);
else if (_sel == this.protocolVersionsImpl.selector) _protocolVersionsImpl = IProtocolVersions(_addr);
else revert("DeployImplementationsOutput: unknown selector");
// forgefmt: disable-end
}
Expand Down Expand Up @@ -250,6 +255,16 @@ contract DeployImplementationsOutput is BaseDeployIO {
return _anchorStateRegistryImpl;
}

function superchainConfigImpl() public view returns (ISuperchainConfig) {
DeployUtils.assertValidContractAddress(address(_superchainConfigImpl));
return _superchainConfigImpl;
}

function protocolVersionsImpl() public view returns (IProtocolVersions) {
DeployUtils.assertValidContractAddress(address(_protocolVersionsImpl));
return _protocolVersionsImpl;
}

// -------- Deployment Assertions --------
function assertValidDeploy(DeployImplementationsInput _dii) public view {
assertValidDelayedWETHImpl(_dii);
Expand Down Expand Up @@ -411,6 +426,7 @@ contract DeployImplementations is Script {

function run(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public {
// Deploy the implementations.
DeploySuperchainImplementations.deploySuperchainImplementationContracts(DeploySuperchainOutput(address(_dio)));
deploySystemConfigImpl(_dio);
deployL1CrossDomainMessengerImpl(_dio);
deployL1ERC721BridgeImpl(_dio);
Expand Down Expand Up @@ -455,6 +471,8 @@ contract DeployImplementations is Script {
l1StandardBridgeImpl: address(_dio.l1StandardBridgeImpl()),
disputeGameFactoryImpl: address(_dio.disputeGameFactoryImpl()),
anchorStateRegistryImpl: address(_dio.anchorStateRegistryImpl()),
superchainConfigImpl: address(_dio.superchainConfigImpl()),
protocolVersionsImpl: address(_dio.protocolVersionsImpl()),
delayedWETHImpl: address(_dio.delayedWETHImpl()),
mipsImpl: address(_dio.mipsSingleton())
});
Expand Down Expand Up @@ -790,6 +808,8 @@ contract DeployImplementationsInterop is DeployImplementations {
IProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();

OPContractsManager.Implementations memory implementations = OPContractsManager.Implementations({
superchainConfigImpl: address(_dio.superchainConfigImpl()),
protocolVersionsImpl: address(_dio.protocolVersionsImpl()),
l1ERC721BridgeImpl: address(_dio.l1ERC721BridgeImpl()),
optimismPortalImpl: address(_dio.optimismPortalImpl()),
systemConfigImpl: address(_dio.systemConfigImpl()),
Expand Down
14 changes: 14 additions & 0 deletions packages/contracts-bedrock/scripts/deploy/DeployOPCM.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ contract DeployOPCMInput is BaseDeployIO {
address internal _permissionedDisputeGame1Blueprint;
address internal _permissionedDisputeGame2Blueprint;

address internal _superchainConfigImpl;
address internal _protocolVersionsImpl;
address internal _l1ERC721BridgeImpl;
address internal _optimismPortalImpl;
address internal _systemConfigImpl;
Expand Down Expand Up @@ -160,6 +162,16 @@ contract DeployOPCMInput is BaseDeployIO {
return _anchorStateRegistryImpl;
}

function superchainConfigImpl() public view returns (address) {
require(_superchainConfigImpl != address(0), "DeployOPCMInput: not set");
return _superchainConfigImpl;
}

function protocolVersionsImpl() public view returns (address) {
require(_protocolVersionsImpl != address(0), "DeployOPCMInput: not set");
return _protocolVersionsImpl;
}

function delayedWETHImpl() public view returns (address) {
require(_delayedWETHImpl != address(0), "DeployOPCMInput: not set");
return _delayedWETHImpl;
Expand Down Expand Up @@ -202,6 +214,8 @@ contract DeployOPCM is Script {
permissionlessDisputeGame2: address(0)
});
OPContractsManager.Implementations memory implementations = OPContractsManager.Implementations({
superchainConfigImpl: address(_doi.superchainConfigImpl()),
protocolVersionsImpl: address(_doi.protocolVersionsImpl()),
l1ERC721BridgeImpl: address(_doi.l1ERC721BridgeImpl()),
optimismPortalImpl: address(_doi.optimismPortalImpl()),
systemConfigImpl: address(_doi.systemConfigImpl()),
Expand Down
59 changes: 34 additions & 25 deletions packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity 0.8.15;

import { Script } from "forge-std/Script.sol";
import { stdToml } from "forge-std/StdToml.sol";

import { Vm } from "forge-std/Vm.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IProtocolVersions, ProtocolVersion } from "interfaces/L1/IProtocolVersions.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
Expand Down Expand Up @@ -310,7 +310,7 @@ contract DeploySuperchain is Script {
deploySuperchainProxyAdmin(_dsi, _dso);

// Deploy and initialize the superchain contracts.
deploySuperchainImplementationContracts(_dsi, _dso);
DeploySuperchainImplementations.deploySuperchainImplementationContracts(_dso);
deployAndInitializeSuperchainConfig(_dsi, _dso);
deployAndInitializeProtocolVersions(_dsi, _dso);

Expand Down Expand Up @@ -341,29 +341,7 @@ contract DeploySuperchain is Script {
}

function deploySuperchainImplementationContracts(DeploySuperchainInput, DeploySuperchainOutput _dso) public {
// Deploy implementation contracts.
vm.startBroadcast(msg.sender);
ISuperchainConfig superchainConfigImpl = ISuperchainConfig(
DeployUtils.createDeterministic({
_name: "SuperchainConfig",
_args: DeployUtils.encodeConstructor(abi.encodeCall(ISuperchainConfig.__constructor__, ())),
_salt: _salt
})
);
IProtocolVersions protocolVersionsImpl = IProtocolVersions(
DeployUtils.createDeterministic({
_name: "ProtocolVersions",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProtocolVersions.__constructor__, ())),
_salt: _salt
})
);
vm.stopBroadcast();

vm.label(address(superchainConfigImpl), "SuperchainConfigImpl");
vm.label(address(protocolVersionsImpl), "ProtocolVersionsImpl");

_dso.set(_dso.superchainConfigImpl.selector, address(superchainConfigImpl));
_dso.set(_dso.protocolVersionsImpl.selector, address(protocolVersionsImpl));
DeploySuperchainImplementations.deploySuperchainImplementationContracts(_dso);
}

function deployAndInitializeSuperchainConfig(DeploySuperchainInput _dsi, DeploySuperchainOutput _dso) public {
Expand Down Expand Up @@ -458,3 +436,34 @@ contract DeploySuperchain is Script {
dso_ = DeploySuperchainOutput(DeployUtils.toIOAddress(msg.sender, "optimism.DeploySuperchainOutput"));
}
}

library DeploySuperchainImplementations {
bytes32 internal constant _salt = keccak256("op-stack-contract-impls-salt-v0");
Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

function deploySuperchainImplementationContracts(DeploySuperchainOutput _dso) public {
// Deploy implementation contracts.
vm.startBroadcast(msg.sender);
ISuperchainConfig superchainConfigImpl = ISuperchainConfig(
DeployUtils.createDeterministic({
_name: "SuperchainConfig",
_args: DeployUtils.encodeConstructor(abi.encodeCall(ISuperchainConfig.__constructor__, ())),
_salt: _salt
})
);
IProtocolVersions protocolVersionsImpl = IProtocolVersions(
DeployUtils.createDeterministic({
_name: "ProtocolVersions",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProtocolVersions.__constructor__, ())),
_salt: _salt
})
);
vm.stopBroadcast();

vm.label(address(superchainConfigImpl), "SuperchainConfigImpl");
vm.label(address(protocolVersionsImpl), "ProtocolVersionsImpl");

_dso.set(_dso.superchainConfigImpl.selector, address(superchainConfigImpl));
_dso.set(_dso.protocolVersionsImpl.selector, address(protocolVersionsImpl));
}
}
19 changes: 17 additions & 2 deletions packages/contracts-bedrock/src/L1/OPContractsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ contract OPContractsManager is ISemver {

/// @notice The latest implementation contracts for the OP Stack.
struct Implementations {
address superchainConfigImpl;
address protocolVersionsImpl;
address l1ERC721BridgeImpl;
address optimismPortalImpl;
address systemConfigImpl;
Expand Down Expand Up @@ -220,6 +222,9 @@ contract OPContractsManager is ISemver {
/// @notice Thrown when the SuperchainConfig of the chain does not match the SuperchainConfig of this OPCM.
error SuperchainConfigMismatch(ISystemConfig systemConfig);

/// @notice Thrown when the SuperchainProxyAdmin does not match the SuperchainConfig's admin.
error SuperchainProxyAdminMismatch();

// -------- Methods --------

constructor(
Expand Down Expand Up @@ -420,12 +425,22 @@ contract OPContractsManager is ISemver {
/// @notice Upgrades a set of chains to the latest implementation contracts
/// @param _opChains Array of OpChain structs, one per chain to upgrade
/// @dev This function is intended to be called via DELEGATECALL from the Upgrade Controller Safe
function upgrade(OpChain[] memory _opChains, OutputRoot[] memory _startingAnchorRoots) external {
function upgrade(
IProxyAdmin _superchainProxyAdmin,
OpChain[] memory _opChains,
OutputRoot[] memory _startingAnchorRoots
)
external
{
if (address(this) == address(thisOPCM)) revert OnlyDelegatecall();

Implementations memory impls = thisOPCM.implementations();

// TODO: upgrading the SuperchainConfig and ProtocolVersions (in a new function)
if (address(_superchainProxyAdmin) != address(0)) {
// Attempt to upgrade. If the ProxyAdmin is not the SuperchainConfig's admin, this will revert.
upgradeTo(_superchainProxyAdmin, address(superchainConfig), impls.superchainConfigImpl);
upgradeTo(_superchainProxyAdmin, address(protocolVersions), impls.protocolVersionsImpl);
}

for (uint256 i = 0; i < _opChains.length; i++) {
ISystemConfig systemConfig = _opChains[i].systemConfigProxy;
Expand Down
22 changes: 17 additions & 5 deletions packages/contracts-bedrock/test/L1/OPContractsManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol";

// Contracts
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
// Interfaces
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
Expand All @@ -25,6 +24,11 @@ import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol";
import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";

// Contracts
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
Expand Down Expand Up @@ -192,6 +196,7 @@ contract OPContractsManager_Upgrade_Harness is CommonTest {

uint256 l2ChainId;
IProxyAdmin proxyAdmin;
IProxyAdmin superchainProxyAdmin;
address upgrader;
OPContractsManager.OpChain[] opChains;
OutputRoot[] startingAnchorRoots;
Expand All @@ -210,6 +215,7 @@ contract OPContractsManager_Upgrade_Harness is CommonTest {
}

proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig)));
superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig)));
upgrader = proxyAdmin.owner();
vm.label(upgrader, "ProxyAdmin Owner");

Expand All @@ -235,6 +241,8 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
OPContractsManager.Implementations memory impls = opcm.implementations();
address oldL1CrossDomainMessenger = addressManager.getAddress("OVM_L1CrossDomainMessenger");

expectEmitUpgraded(impls.superchainConfigImpl, address(superchainConfig));
expectEmitUpgraded(impls.protocolVersionsImpl, address(protocolVersions));
expectEmitUpgraded(impls.systemConfigImpl, address(systemConfig));
vm.expectEmit(address(addressManager));
emit AddressSet("OVM_L1CrossDomainMessenger", impls.l1CrossDomainMessengerImpl, oldL1CrossDomainMessenger);
Expand All @@ -253,7 +261,8 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
emit Upgraded(l2ChainId, opChains[0].systemConfigProxy, address(upgrader));

DelegateCaller(upgrader).dcForward(
address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains, startingAnchorRoots))
address(opcm),
abi.encodeCall(OPContractsManager.upgrade, (superchainProxyAdmin, opChains, startingAnchorRoots))
);

assertEq(impls.systemConfigImpl, EIP1967Helper.getImplementation(address(systemConfig)));
Expand Down Expand Up @@ -286,7 +295,7 @@ contract OPContractsManager_Upgrade_TestFails is OPContractsManager_Upgrade_Harn
function test_upgrade_notDelegateCalled_reverts() public {
vm.prank(upgrader);
vm.expectRevert(OPContractsManager.OnlyDelegatecall.selector);
opcm.upgrade(opChains, startingAnchorRoots);
opcm.upgrade(superchainProxyAdmin, opChains, startingAnchorRoots);
}

function test_upgrade_superchainConfigMismatch_reverts() public {
Expand All @@ -302,7 +311,8 @@ contract OPContractsManager_Upgrade_TestFails is OPContractsManager_Upgrade_Harn
abi.encodeWithSelector(OPContractsManager.SuperchainConfigMismatch.selector, address(systemConfig))
);
DelegateCaller(upgrader).dcForward(
address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains, startingAnchorRoots))
address(opcm),
abi.encodeCall(OPContractsManager.upgrade, (superchainProxyAdmin, opChains, startingAnchorRoots))
);
}
}
Expand Down Expand Up @@ -330,6 +340,8 @@ contract OPContractsManager_AddGameType_Test is Test {
IPreimageOracle oracle = IPreimageOracle(address(new PreimageOracle(126000, 86400)));

OPContractsManager.Implementations memory impls = OPContractsManager.Implementations({
superchainConfigImpl: address(new SuperchainConfig()),
protocolVersionsImpl: address(new ProtocolVersions()),
l1ERC721BridgeImpl: address(new L1ERC721Bridge()),
optimismPortalImpl: address(new OptimismPortal2(1, 1)),
systemConfigImpl: address(new SystemConfig()),
Expand Down
7 changes: 6 additions & 1 deletion packages/contracts-bedrock/test/setup/ForkLive.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol";

Expand Down Expand Up @@ -146,6 +147,9 @@ contract ForkLive is Deployer {
ISystemConfig systemConfig = ISystemConfig(artifacts.mustGetAddress("SystemConfigProxy"));
IProxyAdmin proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig)));

ISuperchainConfig superchainConfig = ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfig"));
IProxyAdmin superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig)));

address upgrader = proxyAdmin.owner();
vm.label(upgrader, "ProxyAdmin Owner");

Expand All @@ -161,7 +165,8 @@ contract ForkLive is Deployer {
// reflecting the production system.
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
DelegateCaller(upgrader).dcForward(
address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains, startingAnchorRoots))
address(opcm),
abi.encodeCall(OPContractsManager.upgrade, (superchainProxyAdmin, opChains, startingAnchorRoots))
);
}

Expand Down

0 comments on commit a943dc7

Please sign in to comment.