Commit 47c00f99 authored by Maurelian's avatar Maurelian Committed by GitHub

feat: Upgrade OPContractsManager to deploy new ASR and dispute games

 (#13803)

* feat: upgrade ASR to new proxy and impl

* feat: semgrep fix for _ prefixed args

* feat: simplify vm.expectCommit call

* save newly deployed contracts in ForkLive

* self review changes

* feat: re-skip tests (unskip moved to later PR)

* feat: Check ImplemenationSet events

* feat: Add dispute game version assertions to check the upgrade

* fix unused imports

* review suggestions

* feat: Avoid some casting

* update snapshots

* refactor dispute game changes into deployAndSetNewGameImpl

* lint

* feat: Deploy using DeployUtils vm.getCode() instead of new

* feat: remove concrete contract imports

* semver lock

* feat: fix non-upgrader test

* lint
parent 969382a3
...@@ -19,6 +19,7 @@ additional_compiler_profiles = [ ...@@ -19,6 +19,7 @@ additional_compiler_profiles = [
compilation_restrictions = [ compilation_restrictions = [
{ paths = "src/dispute/FaultDisputeGame.sol", optimizer_runs = 5000 }, { paths = "src/dispute/FaultDisputeGame.sol", optimizer_runs = 5000 },
{ paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 5000 }, { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 5000 },
{ paths = "src/L1/OPContractsManager.sol", optimizer_runs = 5000 },
] ]
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout'] extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
......
...@@ -16,12 +16,12 @@ ...@@ -16,12 +16,12 @@
"sourceCodeHash": "0x2dd7bf6cbce655b1023a3ad071523bf455aa13fad5d02e1e434af71728cd794c" "sourceCodeHash": "0x2dd7bf6cbce655b1023a3ad071523bf455aa13fad5d02e1e434af71728cd794c"
}, },
"src/L1/OPContractsManager.sol": { "src/L1/OPContractsManager.sol": {
"initCodeHash": "0x9fc601820098fb3308ece91087c9209a4bff049f1f8d1e7c33a7a7a27cf5f96f", "initCodeHash": "0x91a3194df65af1604004fc0cae535a664f4320b8c3d043b4e220e5f41058eb0b",
"sourceCodeHash": "0xcfd0f82cb6481c22841747d9ed9022dc9e6b01a7e03edffb13587bfeae8eaee8" "sourceCodeHash": "0x2c54078dadc80e2a9c8b313acc01b753051206fc0c5d90a5188a88eb3b60c69f"
}, },
"src/L1/OPContractsManagerInterop.sol": { "src/L1/OPContractsManagerInterop.sol": {
"initCodeHash": "0xc7f77833e13a5aa7460df755c60d36068bc10868f9071b4350b139eaa391c071", "initCodeHash": "0xff07c5f0ae28bfe45c696127dea07481a5a58acda12614b354c7b04479c46bb5",
"sourceCodeHash": "0x5a9180a546a0c79baae5f2b42f5110bcae15d3ae8a3e05fa536eb8659774b733" "sourceCodeHash": "0xc2ec936877c5e85425fe261c8394bec43cc7f32fe415c0c7a9acff716e3de599"
}, },
"src/L1/OptimismPortal2.sol": { "src/L1/OptimismPortal2.sol": {
"initCodeHash": "0x969e3687d4497cc168af61e610ba0ae187e80f86aaa7b5d5bb598de19f279f08", "initCodeHash": "0x969e3687d4497cc168af61e610ba0ae187e80f86aaa7b5d5bb598de19f279f08",
......
...@@ -5,7 +5,7 @@ pragma solidity 0.8.15; ...@@ -5,7 +5,7 @@ pragma solidity 0.8.15;
import { Blueprint } from "src/libraries/Blueprint.sol"; import { Blueprint } from "src/libraries/Blueprint.sol";
import { Constants } from "src/libraries/Constants.sol"; import { Constants } from "src/libraries/Constants.sol";
import { Bytes } from "src/libraries/Bytes.sol"; import { Bytes } from "src/libraries/Bytes.sol";
import { Claim, Duration, GameType, GameTypes, OutputRoot } from "src/dispute/lib/Types.sol"; import { Claim, Hash, Duration, GameType, GameTypes, OutputRoot } from "src/dispute/lib/Types.sol";
// Interfaces // Interfaces
import { ISemver } from "interfaces/universal/ISemver.sol"; import { ISemver } from "interfaces/universal/ISemver.sol";
...@@ -141,9 +141,9 @@ contract OPContractsManager is ISemver { ...@@ -141,9 +141,9 @@ contract OPContractsManager is ISemver {
// -------- Constants and Variables -------- // -------- Constants and Variables --------
/// @custom:semver 1.0.0-beta.34 /// @custom:semver 1.0.0-beta.35
function version() public pure virtual returns (string memory) { function version() public pure virtual returns (string memory) {
return "1.0.0-beta.34"; return "1.0.0-beta.35";
} }
/// @notice Address of the SuperchainConfig contract shared by all chains. /// @notice Address of the SuperchainConfig contract shared by all chains.
...@@ -440,38 +440,42 @@ contract OPContractsManager is ISemver { ...@@ -440,38 +440,42 @@ contract OPContractsManager is ISemver {
} }
Implementations memory impls = thisOPCM.implementations(); Implementations memory impls = thisOPCM.implementations();
Blueprints memory bps = thisOPCM.blueprints();
// TODO: upgrading the SuperchainConfig and ProtocolVersions (in a new function) // TODO: upgrading the SuperchainConfig and ProtocolVersions (in a new function)
for (uint256 i = 0; i < _opChains.length; i++) { for (uint256 i = 0; i < _opChains.length; i++) {
ISystemConfig systemConfig = _opChains[i].systemConfigProxy; // After Upgrade 13, we will be able to use systemConfigProxy.getAddresses() here.
// After Upgrade 12, we will be able to use systemConfigProxy.getAddresses() here.
ISystemConfig.Addresses memory opChainAddrs = ISystemConfig.Addresses({ ISystemConfig.Addresses memory opChainAddrs = ISystemConfig.Addresses({
l1CrossDomainMessenger: systemConfig.l1CrossDomainMessenger(), l1CrossDomainMessenger: _opChains[i].systemConfigProxy.l1CrossDomainMessenger(),
l1ERC721Bridge: systemConfig.l1ERC721Bridge(), l1ERC721Bridge: _opChains[i].systemConfigProxy.l1ERC721Bridge(),
l1StandardBridge: systemConfig.l1StandardBridge(), l1StandardBridge: _opChains[i].systemConfigProxy.l1StandardBridge(),
disputeGameFactory: systemConfig.disputeGameFactory(), disputeGameFactory: _opChains[i].systemConfigProxy.disputeGameFactory(),
optimismPortal: systemConfig.optimismPortal(), optimismPortal: _opChains[i].systemConfigProxy.optimismPortal(),
optimismMintableERC20Factory: systemConfig.optimismMintableERC20Factory() optimismMintableERC20Factory: _opChains[i].systemConfigProxy.optimismMintableERC20Factory()
}); });
if (IOptimismPortal2(payable(opChainAddrs.optimismPortal)).superchainConfig() != superchainConfig) { if (IOptimismPortal2(payable(opChainAddrs.optimismPortal)).superchainConfig() != superchainConfig) {
revert SuperchainConfigMismatch(systemConfig); revert SuperchainConfigMismatch(_opChains[i].systemConfigProxy);
} }
IProxyAdmin proxyAdmin = _opChains[i].proxyAdmin;
// -------- Upgrade Contracts Stored in SystemConfig -------- // -------- Upgrade Contracts Stored in SystemConfig --------
upgradeTo(proxyAdmin, address(systemConfig), impls.systemConfigImpl); upgradeTo(_opChains[i].proxyAdmin, address(_opChains[i].systemConfigProxy), impls.systemConfigImpl);
upgradeTo(proxyAdmin, opChainAddrs.l1CrossDomainMessenger, impls.l1CrossDomainMessengerImpl); upgradeTo(_opChains[i].proxyAdmin, opChainAddrs.l1CrossDomainMessenger, impls.l1CrossDomainMessengerImpl);
upgradeTo(proxyAdmin, opChainAddrs.l1ERC721Bridge, impls.l1ERC721BridgeImpl); upgradeTo(_opChains[i].proxyAdmin, opChainAddrs.l1ERC721Bridge, impls.l1ERC721BridgeImpl);
upgradeTo(proxyAdmin, opChainAddrs.l1StandardBridge, impls.l1StandardBridgeImpl); upgradeTo(_opChains[i].proxyAdmin, opChainAddrs.l1StandardBridge, impls.l1StandardBridgeImpl);
upgradeTo(proxyAdmin, opChainAddrs.disputeGameFactory, impls.disputeGameFactoryImpl); upgradeTo(_opChains[i].proxyAdmin, opChainAddrs.disputeGameFactory, impls.disputeGameFactoryImpl);
upgradeTo(proxyAdmin, opChainAddrs.optimismPortal, impls.optimismPortalImpl); upgradeTo(_opChains[i].proxyAdmin, opChainAddrs.optimismPortal, impls.optimismPortalImpl);
upgradeTo(proxyAdmin, opChainAddrs.optimismMintableERC20Factory, impls.optimismMintableERC20FactoryImpl); upgradeTo(
_opChains[i].proxyAdmin,
opChainAddrs.optimismMintableERC20Factory,
impls.optimismMintableERC20FactoryImpl
);
// -------- Discover and Upgrade Proofs Contracts -------- // -------- Discover and Upgrade Proofs Contracts --------
// Starting with the permissioned game, permissioned weth, and anchor state registry, which all chains have. // Note that, the code below uses several independently scoped blocks to avoid stack too deep errors.
// All chains have the Permissioned Dispute Game. We get it first so that we can use it to
// retrieve its WETH and the Anchor State Registry when we need them.
IPermissionedDisputeGame permissionedDisputeGame = IPermissionedDisputeGame( IPermissionedDisputeGame permissionedDisputeGame = IPermissionedDisputeGame(
address( address(
getGameImplementation( getGameImplementation(
...@@ -479,26 +483,83 @@ contract OPContractsManager is ISemver { ...@@ -479,26 +483,83 @@ contract OPContractsManager is ISemver {
) )
) )
); );
IDelayedWETH delayedWETHPermissionedGameProxy = permissionedDisputeGame.weth(); // We're also going to need the l2ChainId below, so we cache it in the outer scope.
IAnchorStateRegistry anchorStateRegistryProxy = permissionedDisputeGame.anchorStateRegistry(); uint256 l2ChainId = permissionedDisputeGame.l2ChainId();
upgradeTo(proxyAdmin, address(anchorStateRegistryProxy), impls.anchorStateRegistryImpl);
upgradeTo(proxyAdmin, address(delayedWETHPermissionedGameProxy), impls.delayedWETHImpl); // Replace the Anchor State Registry Proxy with a new Proxy and Implementation
// TODO: redeploy and replace permissioned game implementation // For this upgrade, we are replacing the previous Anchor State Registry, thus we:
// 1. deploy a new Anchor State Registry proxy
// 2. get the starting anchor root corresponding to the currently respected game type.
// 3. initialize the proxy with that anchor root
IAnchorStateRegistry newAnchorStateRegistryProxy;
{
// Deploy a new proxy, because we're replacing the old one.
newAnchorStateRegistryProxy = IAnchorStateRegistry(
deployProxy({
_l2ChainId: l2ChainId,
_proxyAdmin: _opChains[i].proxyAdmin,
_saltMixer: "v2.0.0",
_contractName: "AnchorStateRegistry"
})
);
// Get the starting anchor root by:
// 1. getting the anchor state registry from the Permissioned Dispute Game.
// 2. getting the respected game type from the OptimismPortal.
// 3. getting the anchor root for the respected game type from the Anchor State Registry.
{
GameType gameType = IOptimismPortal2(payable(opChainAddrs.optimismPortal)).respectedGameType();
(Hash root, uint256 l2BlockNumber) = permissionedDisputeGame.anchorStateRegistry().anchors(gameType);
OutputRoot memory startingAnchorRoot = OutputRoot({ root: root, l2BlockNumber: l2BlockNumber });
upgradeToAndCall(
_opChains[i].proxyAdmin,
address(newAnchorStateRegistryProxy),
impls.anchorStateRegistryImpl,
abi.encodeCall(
IAnchorStateRegistry.initialize,
(
superchainConfig,
IDisputeGameFactory(opChainAddrs.disputeGameFactory),
IOptimismPortal2(payable(opChainAddrs.optimismPortal)),
startingAnchorRoot
)
)
);
}
deployAndSetNewGameImpl({
_proxyAdmin: _opChains[i].proxyAdmin,
_currentGame: IDisputeGame(address(permissionedDisputeGame)),
_newAnchorStateRegistryProxy: newAnchorStateRegistryProxy,
_gameType: GameTypes.PERMISSIONED_CANNON,
_implementations: impls,
_blueprints: bps,
_opChainAddrs: opChainAddrs,
_l2ChainId: l2ChainId
});
}
// Now retrieve the permissionless game. If it exists, upgrade its weth and replace its implementation. // Now retrieve the permissionless game. If it exists, upgrade its weth and replace its implementation.
IFaultDisputeGame faultDisputeGame = IFaultDisputeGame( IFaultDisputeGame permissionlessDisputeGame = IFaultDisputeGame(
address(getGameImplementation(IDisputeGameFactory(opChainAddrs.disputeGameFactory), GameTypes.CANNON)) address(getGameImplementation(IDisputeGameFactory(opChainAddrs.disputeGameFactory), GameTypes.CANNON))
); );
if (address(faultDisputeGame) != address(0)) { if (address(permissionlessDisputeGame) != address(0)) {
IDelayedWETH delayedWETHPermissionlessGameProxy = faultDisputeGame.weth(); deployAndSetNewGameImpl({
upgradeTo(proxyAdmin, address(delayedWETHPermissionlessGameProxy), impls.delayedWETHImpl); _proxyAdmin: _opChains[i].proxyAdmin,
// TODO: redeploy and replace permissionless game implementation _currentGame: IDisputeGame(address(permissionlessDisputeGame)),
_newAnchorStateRegistryProxy: newAnchorStateRegistryProxy,
_gameType: GameTypes.CANNON,
_implementations: impls,
_blueprints: bps,
_opChainAddrs: opChainAddrs,
_l2ChainId: l2ChainId
});
} }
// Emit the upgraded event with the address of the caller. Since this will be a delegatecall, // Emit the upgraded event with the address of the caller. Since this will be a delegatecall,
// the caller will be the value of the ADDRESS opcode. // the caller will be the value of the ADDRESS opcode.
uint256 l2ChainId = permissionedDisputeGame.l2ChainId(); emit Upgraded(l2ChainId, _opChains[i].systemConfigProxy, address(this));
emit Upgraded(l2ChainId, systemConfig, address(this));
} }
} }
...@@ -903,4 +964,74 @@ contract OPContractsManager is ISemver { ...@@ -903,4 +964,74 @@ contract OPContractsManager is ISemver {
if (msg.sender != upgradeController) revert OnlyUpgradeController(); if (msg.sender != upgradeController) revert OnlyUpgradeController();
isRC = _isRC; isRC = _isRC;
} }
function getGameConstructorParams(IFaultDisputeGame _disputeGame)
internal
view
returns (IFaultDisputeGame.GameConstructorParams memory)
{
IFaultDisputeGame.GameConstructorParams memory params = IFaultDisputeGame.GameConstructorParams({
gameType: _disputeGame.gameType(),
absolutePrestate: _disputeGame.absolutePrestate(),
maxGameDepth: _disputeGame.maxGameDepth(),
splitDepth: _disputeGame.splitDepth(),
clockExtension: _disputeGame.clockExtension(),
maxClockDuration: _disputeGame.maxClockDuration(),
vm: _disputeGame.vm(),
weth: _disputeGame.weth(),
anchorStateRegistry: _disputeGame.anchorStateRegistry(),
l2ChainId: _disputeGame.l2ChainId()
});
return params;
}
/// @notice For a given game type, does the following:
/// 1. Get and upgrade the DelayedWETH Proxy
/// 2. Deploy a new game
/// 3. Set the new game as the implementation on the OptimismPortal
function deployAndSetNewGameImpl(
IProxyAdmin _proxyAdmin,
IDisputeGame _currentGame,
IAnchorStateRegistry _newAnchorStateRegistryProxy,
GameType _gameType,
Blueprints memory _blueprints,
Implementations memory _implementations,
ISystemConfig.Addresses memory _opChainAddrs,
uint256 _l2ChainId
)
internal
{
// Get and upgrade the WETH proxy
IDelayedWETH delayedWethProxy = IFaultDisputeGame(address(_currentGame)).weth();
upgradeTo(_proxyAdmin, address(delayedWethProxy), _implementations.delayedWETHImpl);
// Get the constructor params for the game
IFaultDisputeGame.GameConstructorParams memory params =
getGameConstructorParams(IFaultDisputeGame(address(_currentGame)));
params.anchorStateRegistry = IAnchorStateRegistry(address(_newAnchorStateRegistryProxy));
IDisputeGame newGame;
if (GameType.unwrap(_gameType) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON)) {
address proposer = IPermissionedDisputeGame(address(_currentGame)).proposer();
address challenger = IPermissionedDisputeGame(address(_currentGame)).challenger();
newGame = IDisputeGame(
Blueprint.deployFrom(
_blueprints.permissionedDisputeGame1,
_blueprints.permissionedDisputeGame2,
computeSalt(_l2ChainId, "v2.0.0", "PermissionedDisputeGame"),
encodePermissionedFDGConstructor(params, proposer, challenger)
)
);
} else {
newGame = IDisputeGame(
Blueprint.deployFrom(
_blueprints.permissionlessDisputeGame1,
_blueprints.permissionlessDisputeGame2,
computeSalt(_l2ChainId, "v2.0.0", "PermissionlessDisputeGame"),
encodePermissionlessFDGConstructor(params)
)
);
}
IDisputeGameFactory(_opChainAddrs.disputeGameFactory).setImplementation(_gameType, IDisputeGame(newGame));
}
} }
...@@ -12,9 +12,9 @@ import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; ...@@ -12,9 +12,9 @@ import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol"; import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol";
contract OPContractsManagerInterop is OPContractsManager { contract OPContractsManagerInterop is OPContractsManager {
/// @custom:semver +interop-beta.2 /// @custom:semver +interop-beta.3
function version() public pure override returns (string memory) { function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop-beta.2"); return string.concat(super.version(), "+interop-beta.3");
} }
constructor( constructor(
......
...@@ -27,25 +27,14 @@ import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; ...@@ -27,25 +27,14 @@ import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol";
import { ISemver } from "interfaces/universal/ISemver.sol";
// Contracts // Contracts
import { OPContractsManager } from "src/L1/OPContractsManager.sol"; import { OPContractsManager } from "src/L1/OPContractsManager.sol";
import { Blueprint } from "src/libraries/Blueprint.sol"; import { Blueprint } from "src/libraries/Blueprint.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
import { SystemConfig } from "src/L1/SystemConfig.sol";
import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol";
import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol";
import { L1StandardBridge } from "src/L1/L1StandardBridge.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; import { IBigStepper } from "interfaces/dispute/IBigStepper.sol";
import { DelayedWETH } from "src/dispute/DelayedWETH.sol";
import { MIPS } from "src/cannon/MIPS.sol";
import { GameType, Duration, Hash, Claim } from "src/dispute/lib/LibUDT.sol"; import { GameType, Duration, Hash, Claim } from "src/dispute/lib/LibUDT.sol";
import { OutputRoot } from "src/dispute/lib/Types.sol"; import { OutputRoot, GameTypes } from "src/dispute/lib/Types.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
// Exposes internal functions for testing. // Exposes internal functions for testing.
contract OPContractsManager_Harness is OPContractsManager { contract OPContractsManager_Harness is OPContractsManager {
...@@ -208,6 +197,12 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { ...@@ -208,6 +197,12 @@ contract OPContractsManager_Upgrade_Harness is CommonTest {
// The AddressSet event emitted by the AddressManager contract. // The AddressSet event emitted by the AddressManager contract.
event AddressSet(string indexed name, address newAddress, address oldAddress); event AddressSet(string indexed name, address newAddress, address oldAddress);
// The AdminChanged event emitted by the Proxy contract at init time or when the admin is changed.
event AdminChanged(address previousAdmin, address newAdmin);
// The ImplementationSet event emitted by the DisputeGameFactory contract.
event ImplementationSet(address indexed impl, GameType indexed gameType);
uint256 l2ChainId; uint256 l2ChainId;
IProxyAdmin proxyAdmin; IProxyAdmin proxyAdmin;
address upgrader; address upgrader;
...@@ -247,8 +242,16 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { ...@@ -247,8 +242,16 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
vm.etch(delegateCaller, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller")); vm.etch(delegateCaller, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
IOPContractsManager.Implementations memory impls = opcm.implementations(); IOPContractsManager.Implementations memory impls = opcm.implementations();
// Cache the old L1xDM address so we can look for it in the AddressManager's event
address oldL1CrossDomainMessenger = addressManager.getAddress("OVM_L1CrossDomainMessenger"); address oldL1CrossDomainMessenger = addressManager.getAddress("OVM_L1CrossDomainMessenger");
// Predict the address of the new AnchorStateRegistry proxy
bytes32 salt = keccak256(abi.encode(l2ChainId, "v2.0.0", "AnchorStateRegistry"));
bytes memory initCode = bytes.concat(vm.getCode("Proxy"), abi.encode(proxyAdmin));
address newAnchorStateRegistryProxy = vm.computeCreate2Address(salt, keccak256(initCode), delegateCaller);
vm.label(newAnchorStateRegistryProxy, "NewAnchorStateRegistryProxy");
expectEmitUpgraded(impls.systemConfigImpl, address(systemConfig)); expectEmitUpgraded(impls.systemConfigImpl, address(systemConfig));
vm.expectEmit(address(addressManager)); vm.expectEmit(address(addressManager));
emit AddressSet("OVM_L1CrossDomainMessenger", impls.l1CrossDomainMessengerImpl, oldL1CrossDomainMessenger); emit AddressSet("OVM_L1CrossDomainMessenger", impls.l1CrossDomainMessengerImpl, oldL1CrossDomainMessenger);
...@@ -258,15 +261,25 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { ...@@ -258,15 +261,25 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
expectEmitUpgraded(impls.disputeGameFactoryImpl, address(disputeGameFactory)); expectEmitUpgraded(impls.disputeGameFactoryImpl, address(disputeGameFactory));
expectEmitUpgraded(impls.optimismPortalImpl, address(optimismPortal2)); expectEmitUpgraded(impls.optimismPortalImpl, address(optimismPortal2));
expectEmitUpgraded(impls.optimismMintableERC20FactoryImpl, address(l1OptimismMintableERC20Factory)); expectEmitUpgraded(impls.optimismMintableERC20FactoryImpl, address(l1OptimismMintableERC20Factory));
expectEmitUpgraded(impls.anchorStateRegistryImpl, address(anchorStateRegistry)); vm.expectEmit(address(newAnchorStateRegistryProxy));
emit AdminChanged(address(0), address(proxyAdmin));
expectEmitUpgraded(impls.anchorStateRegistryImpl, address(newAnchorStateRegistryProxy));
expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWETHPermissionedGameProxy)); expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWETHPermissionedGameProxy));
// We don't yet know the address of the new permissionedGame which will be deployed by the
// OPContractsManager.upgrade() call, so ignore the first topic.
vm.expectEmit(false, true, true, true, address(disputeGameFactory));
emit ImplementationSet(address(0), GameTypes.PERMISSIONED_CANNON);
if (address(delayedWeth) != address(0)) { if (address(delayedWeth) != address(0)) {
expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWeth)); expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWeth));
// Ignore the first topic for the same reason as the previous comment.
vm.expectEmit(false, true, true, true, address(disputeGameFactory));
emit ImplementationSet(address(0), GameTypes.CANNON);
} }
vm.expectEmit(true, true, true, true, address(delegateCaller)); vm.expectEmit(address(delegateCaller));
emit Upgraded(l2ChainId, opChains[0].systemConfigProxy, address(delegateCaller)); emit Upgraded(l2ChainId, opChains[0].systemConfigProxy, address(delegateCaller));
DelegateCaller(delegateCaller).dcForward(address(opcm), abi.encodeCall(IOPContractsManager.upgrade, (opChains))); DelegateCaller(delegateCaller).dcForward(address(opcm), abi.encodeCall(IOPContractsManager.upgrade, (opChains)));
vm.stopPrank();
if (delegateCaller == upgrader) { if (delegateCaller == upgrader) {
assertFalse(opcm.isRC(), "isRC should be false"); assertFalse(opcm.isRC(), "isRC should be false");
...@@ -275,6 +288,8 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { ...@@ -275,6 +288,8 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
Bytes.slice(releaseBytes, releaseBytes.length - 3, 3), "-rc", "release should not end with '-rc'" Bytes.slice(releaseBytes, releaseBytes.length - 3, 3), "-rc", "release should not end with '-rc'"
); );
} }
// Check the implementations of the core addresses
assertEq(impls.systemConfigImpl, EIP1967Helper.getImplementation(address(systemConfig))); assertEq(impls.systemConfigImpl, EIP1967Helper.getImplementation(address(systemConfig)));
assertEq(impls.l1ERC721BridgeImpl, EIP1967Helper.getImplementation(address(l1ERC721Bridge))); assertEq(impls.l1ERC721BridgeImpl, EIP1967Helper.getImplementation(address(l1ERC721Bridge)));
assertEq(impls.disputeGameFactoryImpl, EIP1967Helper.getImplementation(address(disputeGameFactory))); assertEq(impls.disputeGameFactoryImpl, EIP1967Helper.getImplementation(address(disputeGameFactory)));
...@@ -286,13 +301,19 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { ...@@ -286,13 +301,19 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
assertEq(impls.l1StandardBridgeImpl, EIP1967Helper.getImplementation(address(l1StandardBridge))); assertEq(impls.l1StandardBridgeImpl, EIP1967Helper.getImplementation(address(l1StandardBridge)));
assertEq(impls.l1CrossDomainMessengerImpl, addressManager.getAddress("OVM_L1CrossDomainMessenger")); assertEq(impls.l1CrossDomainMessengerImpl, addressManager.getAddress("OVM_L1CrossDomainMessenger"));
assertEq(impls.anchorStateRegistryImpl, EIP1967Helper.getImplementation(address(anchorStateRegistry))); // Check the implementations of the FP contracts
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth))); assertEq(impls.anchorStateRegistryImpl, EIP1967Helper.getImplementation(address(newAnchorStateRegistryProxy)));
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWETHPermissionedGameProxy)));
// Check that the PermissionedDisputeGame is upgraded to the expected version
assertEq(
ISemver(address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON))).version(), "1.4.0-beta.1"
);
if (address(delayedWeth) != address(0)) { if (address(delayedWeth) != address(0)) {
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth))); assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth)));
// Check that the PermissionlessDisputeGame is upgraded to the expected version
assertEq(ISemver(address(disputeGameFactory.gameImpls(GameTypes.CANNON))).version(), "1.4.0-beta.1");
} }
// TODO: ensure dispute games are updated (upcoming PR)
} }
function test_upgrade_succeeds() public { function test_upgrade_succeeds() public {
...@@ -315,7 +336,16 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { ...@@ -315,7 +336,16 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
} }
// Set the proxy admin owner to be the non-upgrade controller // Set the proxy admin owner to be the non-upgrade controller
vm.store(address(proxyAdmin), bytes32(0), bytes32(uint256(uint160(_nonUpgradeController)))); vm.store(
address(proxyAdmin),
bytes32(ForgeArtifacts.getSlot("ProxyAdmin", "_owner").slot),
bytes32(uint256(uint160(_nonUpgradeController)))
);
vm.store(
address(disputeGameFactory),
bytes32(ForgeArtifacts.getSlot("DisputeGameFactory", "_owner").slot),
bytes32(uint256(uint160(_nonUpgradeController)))
);
// Run the upgrade test and checks // Run the upgrade test and checks
runUpgradeTestAndChecks(_nonUpgradeController); runUpgradeTestAndChecks(_nonUpgradeController);
...@@ -408,19 +438,19 @@ contract OPContractsManager_AddGameType_Test is Test { ...@@ -408,19 +438,19 @@ contract OPContractsManager_AddGameType_Test is Test {
(blueprints.permissionlessDisputeGame1, blueprints.permissionlessDisputeGame2) = (blueprints.permissionlessDisputeGame1, blueprints.permissionlessDisputeGame2) =
Blueprint.create(vm.getCode("FaultDisputeGame"), salt); Blueprint.create(vm.getCode("FaultDisputeGame"), salt);
IPreimageOracle oracle = IPreimageOracle(address(new PreimageOracle(126000, 86400))); IPreimageOracle oracle = IPreimageOracle(DeployUtils.create1("PreimageOracle", abi.encode(126000, 86400)));
IOPContractsManager.Implementations memory impls = IOPContractsManager.Implementations({ IOPContractsManager.Implementations memory impls = IOPContractsManager.Implementations({
l1ERC721BridgeImpl: address(new L1ERC721Bridge()), l1ERC721BridgeImpl: DeployUtils.create1("L1ERC721Bridge"),
optimismPortalImpl: address(new OptimismPortal2(1, 1)), optimismPortalImpl: DeployUtils.create1("OptimismPortal2", abi.encode(1, 1)),
systemConfigImpl: address(new SystemConfig()), systemConfigImpl: DeployUtils.create1("SystemConfig"),
optimismMintableERC20FactoryImpl: address(new OptimismMintableERC20Factory()), optimismMintableERC20FactoryImpl: DeployUtils.create1("OptimismMintableERC20Factory"),
l1CrossDomainMessengerImpl: address(new L1CrossDomainMessenger()), l1CrossDomainMessengerImpl: DeployUtils.create1("L1CrossDomainMessenger"),
l1StandardBridgeImpl: address(new L1StandardBridge()), l1StandardBridgeImpl: DeployUtils.create1("L1StandardBridge"),
disputeGameFactoryImpl: address(new DisputeGameFactory()), disputeGameFactoryImpl: DeployUtils.create1("DisputeGameFactory"),
anchorStateRegistryImpl: address(new AnchorStateRegistry()), anchorStateRegistryImpl: DeployUtils.create1("AnchorStateRegistry"),
delayedWETHImpl: address(new DelayedWETH(3)), delayedWETHImpl: DeployUtils.create1("DelayedWETH", abi.encode(3)),
mipsImpl: address(new MIPS(oracle)) mipsImpl: DeployUtils.create1("MIPS", abi.encode(oracle))
}); });
vm.etch(address(superchainConfigProxy), hex"01"); vm.etch(address(superchainConfigProxy), hex"01");
...@@ -451,7 +481,12 @@ contract OPContractsManager_AddGameType_Test is Test { ...@@ -451,7 +481,12 @@ contract OPContractsManager_AddGameType_Test is Test {
}), }),
basefeeScalar: 1, basefeeScalar: 1,
blobBasefeeScalar: 1, blobBasefeeScalar: 1,
startingAnchorRoot: abi.encode(OutputRoot({ root: Hash.wrap(hex"dead"), l2BlockNumber: 0 })), startingAnchorRoot: abi.encode(
OutputRoot({
root: Hash.wrap(0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef),
l2BlockNumber: 0
})
),
l2ChainId: 100, l2ChainId: 100,
saltMixer: "hello", saltMixer: "hello",
gasLimit: 30_000_000, gasLimit: 30_000_000,
...@@ -487,7 +522,7 @@ contract OPContractsManager_AddGameType_Test is Test { ...@@ -487,7 +522,7 @@ contract OPContractsManager_AddGameType_Test is Test {
} }
function test_addGameType_reusedDelayedWETH_succeeds() public { function test_addGameType_reusedDelayedWETH_succeeds() public {
IDelayedWETH delayedWETH = IDelayedWETH(payable(address(new DelayedWETH(1)))); IDelayedWETH delayedWETH = IDelayedWETH(payable(address(DeployUtils.create1("DelayedWETH", abi.encode(1)))));
vm.etch(address(delayedWETH), hex"01"); vm.etch(address(delayedWETH), hex"01");
IOPContractsManager.AddGameInput memory input = newGameInputFactory(false); IOPContractsManager.AddGameInput memory input = newGameInputFactory(false);
input.delayedWETH = delayedWETH; input.delayedWETH = delayedWETH;
......
...@@ -152,6 +152,8 @@ contract CommonTest is Test, Setup, Events { ...@@ -152,6 +152,8 @@ contract CommonTest is Test, Setup, Events {
string(abi.encodePacked("L1-", NativeL2Token.symbol())) string(abi.encodePacked("L1-", NativeL2Token.symbol()))
) )
); );
console.log("CommonTest: SetUp complete!");
} }
/// @dev Helper function that wraps `TransactionDeposited` event. /// @dev Helper function that wraps `TransactionDeposited` event.
......
...@@ -17,11 +17,13 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; ...@@ -17,11 +17,13 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
// Interfaces // Interfaces
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol";
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol";
import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol";
/// @title ForkLive /// @title ForkLive
/// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an /// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an
...@@ -156,6 +158,22 @@ contract ForkLive is Deployer { ...@@ -156,6 +158,22 @@ contract ForkLive is Deployer {
// reflecting the production system. // reflecting the production system.
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller")); vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(IOPContractsManager.upgrade, (opChains))); DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(IOPContractsManager.upgrade, (opChains)));
console.log("ForkLive: Saving newly deployed contracts");
// A new ASR and new dispute games were deployed, so we need to update them
IDisputeGameFactory disputeGameFactory =
IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy"));
address permissionedDisputeGame = address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON));
artifacts.save("PermissionedDisputeGame", permissionedDisputeGame);
address permissionlessDisputeGame = address(disputeGameFactory.gameImpls(GameTypes.CANNON));
if (permissionlessDisputeGame != address(0)) {
artifacts.save("PermissionlessDisputeGame", address(permissionlessDisputeGame));
}
IAnchorStateRegistry newAnchorStateRegistry =
IPermissionedDisputeGame(permissionedDisputeGame).anchorStateRegistry();
artifacts.save("AnchorStateRegistryProxy", address(newAnchorStateRegistry));
} }
/// @notice Saves the proxy and implementation addresses for a contract name /// @notice Saves the proxy and implementation addresses for a contract name
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment