Commit e90ae518 authored by Maurelian's avatar Maurelian Committed by GitHub

OPCM upgrade full PoC (#13574)

* feat: Implement OPCM upgrade

* feat: better comment

* feat: Move vars to Setup where they belong

* gas snapshot
parent bcf59234
......@@ -44,6 +44,7 @@ interface ISystemConfig {
function gasLimit() external view returns (uint64);
function eip1559Denominator() external view returns (uint32);
function eip1559Elasticity() external view returns (uint32);
function getAddresses() external view returns (Addresses memory);
function initialize(
address _owner,
uint32 _basefeeScalar,
......
......@@ -89,6 +89,7 @@ contract DeployConfig is Script {
address public customGasTokenAddress;
bool public useInterop;
bool public useUpgradedFork;
function read(string memory _path) public {
console.log("DeployConfig: reading file %s", _path);
......@@ -174,6 +175,7 @@ contract DeployConfig is Script {
customGasTokenAddress = _readOr(_json, "$.customGasTokenAddress", address(0));
useInterop = _readOr(_json, "$.useInterop", false);
useUpgradedFork;
}
function fork() public view returns (Fork fork_) {
......@@ -236,6 +238,17 @@ contract DeployConfig is Script {
customGasTokenAddress = _token;
}
/// @notice Allow the `useUpgradedFork` config to be overridden in testing environments
/// @dev When true, the forked system WILL be upgraded in setUp().
/// When false, the forked system WILL NOT be upgraded in setUp().
/// This function does nothing when not testing in a forked environment.
/// Generally the only time you should call this function is if you want to
/// call opcm.upgrade() in the test itself, rather than have the upgraded
/// system be deployed in setUp().
function setUseUpgradedFork(bool _useUpgradedFork) public {
useUpgradedFork = _useUpgradedFork;
}
function latestGenesisFork() internal view returns (Fork) {
if (l2GenesisHoloceneTimeOffset == 0) {
return Fork.HOLOCENE;
......
GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7567)
GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5567)
GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7589)
GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5589)
GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175722)
GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5144)
GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531)
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597)
GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158553)
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7619)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 356487)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2954716)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 551591)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4063784)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 450277)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3496176)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 59849)
\ No newline at end of file
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 551627)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4063775)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 450267)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3496188)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 59798)
\ No newline at end of file
......@@ -600,6 +600,31 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfigProxy",
"type": "address"
},
{
"internalType": "contract IProxyAdmin",
"name": "proxyAdmin",
"type": "address"
}
],
"internalType": "struct OPContractsManager.OpChain[]",
"name": "_opChains",
"type": "tuple[]"
}
],
"name": "upgrade",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "version",
......@@ -610,7 +635,7 @@
"type": "string"
}
],
"stateMutability": "view",
"stateMutability": "pure",
"type": "function"
},
{
......@@ -638,6 +663,31 @@
"name": "Deployed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "upgrader",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{
"inputs": [
{
......@@ -731,6 +781,17 @@
"name": "ReservedBitsSet",
"type": "error"
},
{
"inputs": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
}
],
"name": "SuperchainConfigMismatch",
"type": "error"
},
{
"inputs": [
{
......
......@@ -600,6 +600,31 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfigProxy",
"type": "address"
},
{
"internalType": "contract IProxyAdmin",
"name": "proxyAdmin",
"type": "address"
}
],
"internalType": "struct OPContractsManager.OpChain[]",
"name": "_opChains",
"type": "tuple[]"
}
],
"name": "upgrade",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "version",
......@@ -610,7 +635,7 @@
"type": "string"
}
],
"stateMutability": "view",
"stateMutability": "pure",
"type": "function"
},
{
......@@ -638,6 +663,31 @@
"name": "Deployed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "upgrader",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{
"inputs": [
{
......@@ -731,6 +781,17 @@
"name": "ReservedBitsSet",
"type": "error"
},
{
"inputs": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
}
],
"name": "SuperchainConfigMismatch",
"type": "error"
},
{
"inputs": [
{
......
......@@ -238,6 +238,51 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getAddresses",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "l1CrossDomainMessenger",
"type": "address"
},
{
"internalType": "address",
"name": "l1ERC721Bridge",
"type": "address"
},
{
"internalType": "address",
"name": "l1StandardBridge",
"type": "address"
},
{
"internalType": "address",
"name": "disputeGameFactory",
"type": "address"
},
{
"internalType": "address",
"name": "optimismPortal",
"type": "address"
},
{
"internalType": "address",
"name": "optimismMintableERC20Factory",
"type": "address"
}
],
"internalType": "struct SystemConfig.Addresses",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
......
......@@ -259,6 +259,51 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getAddresses",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "l1CrossDomainMessenger",
"type": "address"
},
{
"internalType": "address",
"name": "l1ERC721Bridge",
"type": "address"
},
{
"internalType": "address",
"name": "l1StandardBridge",
"type": "address"
},
{
"internalType": "address",
"name": "disputeGameFactory",
"type": "address"
},
{
"internalType": "address",
"name": "optimismPortal",
"type": "address"
},
{
"internalType": "address",
"name": "optimismMintableERC20Factory",
"type": "address"
}
],
"internalType": "struct SystemConfig.Addresses",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
......
......@@ -16,8 +16,12 @@
"sourceCodeHash": "0xc6613d35d1ad95cbef26a503a10b5dd8663ceb80426f8c528835d39f79e4b4cf"
},
"src/L1/OPContractsManager.sol": {
"initCodeHash": "0xd523359106bfdca4189401bba564d2856a7122b705f9ad2698b8b43bb28169c8",
"sourceCodeHash": "0x823041c951d9df921295b25f9151b57292a64de98fec2c12849e9fe6a3fb635d"
"initCodeHash": "0xa277d25e1aae34f68e9e8a0814c34f6adada5248992dc5e62831ef0082f130fb",
"sourceCodeHash": "0xaa2c1ae210bf8c53b21e8fe3280bf17040118530eafd1f33e8ed64bc17ee4a17"
},
"src/L1/OPContractsManagerInterop.sol": {
"initCodeHash": "0x5cbfb22cb4ca0465a0bc8d87034763f9a103384ff60ac88af8a4c2ced7c96b7d",
"sourceCodeHash": "0x1bbe8f918f1d5b1cc75924cdf23b10664b890fd306c2aa5d195a7b4177670431"
},
"src/L1/OptimismPortal2.sol": {
"initCodeHash": "0x969e3687d4497cc168af61e610ba0ae187e80f86aaa7b5d5bb598de19f279f08",
......@@ -36,12 +40,12 @@
"sourceCodeHash": "0xafa784ea78818a382ff3a61e2d84be58c7978110c06b9273db68c0213ead02d3"
},
"src/L1/SystemConfig.sol": {
"initCodeHash": "0xf0bfbb889687af7d4e006f40b269bbd9e4d967cdd9c1f29900017ff11b1f5095",
"sourceCodeHash": "0x2dde897735c0cd699f15a1927bf6f75c2da220c1934021ee93315708d5b5f995"
"initCodeHash": "0x48e379dbb7a457ea5d7ab11e42b7b30377de9fe4bcc8a0a4b1ce8591652da6f4",
"sourceCodeHash": "0x0cfa6d791e217bd6650e1155ead95781505cd364b698cbea44c7684b1e506d57"
},
"src/L1/SystemConfigInterop.sol": {
"initCodeHash": "0xd89526ba331c24f8ca5ce1eef1554ad573e3aa9e6845a5b0ec23ee8f3497a84a",
"sourceCodeHash": "0x10806bbaa0d0e1dca571b720bd9690dd55cbf57038ab5887ecfdce689b0ae94e"
"initCodeHash": "0xa5a43846dbf17233c3ac5bb845798b3dbb95e4773249e9b74cb88626a5e77132",
"sourceCodeHash": "0x893478f9816eb4e0764ed275a3ff27d8b9aa264ce5c5f4f0011cecfcc3638e47"
},
"src/L2/BaseFeeVault.sol": {
"initCodeHash": "0xc403d4c555d8e69a2699e01d192ae7327136701fa02da10a6d75a584b3c364c9",
......
......@@ -112,6 +112,12 @@ contract OPContractsManager is ISemver {
address mipsImpl;
}
/// @notice The input required to identify a chain for upgrading.
struct OpChain {
ISystemConfig systemConfigProxy;
IProxyAdmin proxyAdmin;
}
struct AddGameInput {
string saltMixer;
ISystemConfig systemConfig;
......@@ -135,8 +141,10 @@ contract OPContractsManager is ISemver {
// -------- Constants and Variables --------
/// @custom:semver 1.0.0-beta.32
string public constant version = "1.0.0-beta.32";
/// @custom:semver 1.0.0-beta.33
function version() public pure virtual returns (string memory) {
return "1.0.0-beta.33";
}
/// @notice Address of the SuperchainConfig contract shared by all chains.
ISuperchainConfig public immutable superchainConfig;
......@@ -168,6 +176,11 @@ contract OPContractsManager is ISemver {
/// @param deployOutput ABI-encoded output of the deployment.
event Deployed(uint256 indexed l2ChainId, address indexed deployer, bytes deployOutput);
/// @notice Emitted when a chain is upgraded
/// @param systemConfig Address of the chain's SystemConfig contract
/// @param upgrader Address that initiated the upgrade
event Upgraded(uint256 indexed l2ChainId, ISystemConfig indexed systemConfig, address indexed upgrader);
// -------- Errors --------
/// @notice Thrown when an address is the zero address.
......@@ -197,6 +210,9 @@ contract OPContractsManager is ISemver {
/// @notice Thrown when game configs passed to addGameType are invalid.
error InvalidGameConfigs();
/// @notice Thrown when the SuperchainConfig of the chain does not match the SuperchainConfig of this OPCM.
error SuperchainConfigMismatch(ISystemConfig systemConfig);
// -------- Methods --------
constructor(
......@@ -318,25 +334,25 @@ contract OPContractsManager is ISemver {
bytes memory data;
data = encodeL1ERC721BridgeInitializer(output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin, address(output.l1ERC721BridgeProxy), implementation.l1ERC721BridgeImpl, data
);
data = encodeOptimismPortalInitializer(output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin, address(output.optimismPortalProxy), implementation.optimismPortalImpl, data
);
// First we upgrade the implementation so it's version can be retrieved, then we initialize
// it afterwards. See the comments in encodeSystemConfigInitializer to learn more.
output.opChainProxyAdmin.upgrade(payable(address(output.systemConfigProxy)), implementation.systemConfigImpl);
upgradeTo(output.opChainProxyAdmin, payable(address(output.systemConfigProxy)), implementation.systemConfigImpl);
data = encodeSystemConfigInitializer(_input, output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin, address(output.systemConfigProxy), implementation.systemConfigImpl, data
);
data = encodeOptimismMintableERC20FactoryInitializer(output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin,
address(output.optimismMintableERC20FactoryProxy),
implementation.optimismMintableERC20FactoryImpl,
......@@ -344,7 +360,7 @@ contract OPContractsManager is ISemver {
);
data = encodeL1CrossDomainMessengerInitializer(output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin,
address(output.l1CrossDomainMessengerProxy),
implementation.l1CrossDomainMessengerImpl,
......@@ -352,13 +368,13 @@ contract OPContractsManager is ISemver {
);
data = encodeL1StandardBridgeInitializer(output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin, address(output.l1StandardBridgeProxy), implementation.l1StandardBridgeImpl, data
);
data = encodeDelayedWETHInitializer(_input);
// Eventually we will switch from DelayedWETHPermissionedGameProxy to DelayedWETHPermissionlessGameProxy.
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin,
address(output.delayedWETHPermissionedGameProxy),
implementation.delayedWETHImpl,
......@@ -367,7 +383,7 @@ contract OPContractsManager is ISemver {
// We set the initial owner to this contract, set game implementations, then transfer ownership.
data = encodeDisputeGameFactoryInitializer();
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin,
address(output.disputeGameFactoryProxy),
implementation.disputeGameFactoryImpl,
......@@ -379,7 +395,7 @@ contract OPContractsManager is ISemver {
output.disputeGameFactoryProxy.transferOwnership(address(_input.roles.opChainProxyAdminOwner));
data = encodeAnchorStateRegistryInitializer(_input, output);
upgradeAndCall(
upgradeToAndCall(
output.opChainProxyAdmin,
address(output.anchorStateRegistryProxy),
implementation.anchorStateRegistryImpl,
......@@ -394,6 +410,75 @@ contract OPContractsManager is ISemver {
return output;
}
/// @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) external {
if (address(this) == address(thisOPCM)) revert OnlyDelegatecall();
Implementations memory impls = thisOPCM.implementations();
// TODO: upgrading the SuperchainConfig and ProtocolVersions (in a new function)
for (uint256 i = 0; i < _opChains.length; i++) {
ISystemConfig systemConfig = _opChains[i].systemConfigProxy;
// After Upgrade 12, we will be able to use systemConfigProxy.getAddresses() here.
ISystemConfig.Addresses memory opChainAddrs = ISystemConfig.Addresses({
l1CrossDomainMessenger: systemConfig.l1CrossDomainMessenger(),
l1ERC721Bridge: systemConfig.l1ERC721Bridge(),
l1StandardBridge: systemConfig.l1StandardBridge(),
disputeGameFactory: systemConfig.disputeGameFactory(),
optimismPortal: systemConfig.optimismPortal(),
optimismMintableERC20Factory: systemConfig.optimismMintableERC20Factory()
});
if (IOptimismPortal2(payable(opChainAddrs.optimismPortal)).superchainConfig() != superchainConfig) {
revert SuperchainConfigMismatch(systemConfig);
}
IProxyAdmin proxyAdmin = _opChains[i].proxyAdmin;
// -------- Upgrade Contracts Stored in SystemConfig --------
upgradeTo(proxyAdmin, address(systemConfig), impls.systemConfigImpl);
upgradeTo(proxyAdmin, opChainAddrs.l1CrossDomainMessenger, impls.l1CrossDomainMessengerImpl);
upgradeTo(proxyAdmin, opChainAddrs.l1ERC721Bridge, impls.l1ERC721BridgeImpl);
upgradeTo(proxyAdmin, opChainAddrs.l1StandardBridge, impls.l1StandardBridgeImpl);
upgradeTo(proxyAdmin, opChainAddrs.disputeGameFactory, impls.disputeGameFactoryImpl);
upgradeTo(proxyAdmin, opChainAddrs.optimismPortal, impls.optimismPortalImpl);
upgradeTo(proxyAdmin, opChainAddrs.optimismMintableERC20Factory, impls.optimismMintableERC20FactoryImpl);
// -------- Discover and Upgrade Proofs Contracts --------
// Starting with the permissioned game, permissioned weth, and anchor state registry, which all chains have.
IPermissionedDisputeGame permissionedDisputeGame = IPermissionedDisputeGame(
address(
getGameImplementation(
IDisputeGameFactory(opChainAddrs.disputeGameFactory), GameTypes.PERMISSIONED_CANNON
)
)
);
IDelayedWETH delayedWETHPermissionedGameProxy = permissionedDisputeGame.weth();
IAnchorStateRegistry anchorStateRegistryProxy = permissionedDisputeGame.anchorStateRegistry();
upgradeTo(proxyAdmin, address(anchorStateRegistryProxy), impls.anchorStateRegistryImpl);
upgradeTo(proxyAdmin, address(delayedWETHPermissionedGameProxy), impls.delayedWETHImpl);
// TODO: redeploy and replace permissioned game implementation
// Now retrieve the permissionless game. If it exists, upgrade its weth and replace its implementation.
IFaultDisputeGame faultDisputeGame = IFaultDisputeGame(
address(getGameImplementation(IDisputeGameFactory(opChainAddrs.disputeGameFactory), GameTypes.CANNON))
);
if (address(faultDisputeGame) != address(0)) {
IDelayedWETH delayedWETHPermissionlessGameProxy = faultDisputeGame.weth();
upgradeTo(proxyAdmin, address(delayedWETHPermissionlessGameProxy), impls.delayedWETHImpl);
// TODO: redeploy and replace permissionless game implementation
}
// 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.
uint256 l2ChainId = permissionedDisputeGame.l2ChainId();
emit Upgraded(l2ChainId, systemConfig, address(this));
}
}
/// @notice addGameType deploys a new dispute game and links it to the DisputeGameFactory. The inputted _gameConfigs
/// must be added in ascending GameType order.
function addGameType(AddGameInput[] memory _gameConfigs) external returns (AddGameOutput[] memory) {
......@@ -419,8 +504,8 @@ contract OPContractsManager is ISemver {
// Grab the FDG from the SystemConfig.
IFaultDisputeGame fdg = IFaultDisputeGame(
address(
IDisputeGameFactory(gameConfig.systemConfig.disputeGameFactory()).gameImpls(
GameTypes.PERMISSIONED_CANNON
getGameImplementation(
IDisputeGameFactory(gameConfig.systemConfig.disputeGameFactory()), GameTypes.PERMISSIONED_CANNON
)
)
);
......@@ -435,7 +520,7 @@ contract OPContractsManager is ISemver {
);
// Initialize the proxy.
upgradeAndCall(
upgradeToAndCall(
gameConfig.proxyAdmin,
address(outputs[i].delayedWETH),
thisOPCM.implementations().delayedWETHImpl,
......@@ -743,7 +828,7 @@ contract OPContractsManager is ISemver {
/// @notice Makes an external call to the target to initialize the proxy with the specified data.
/// First performs safety checks to ensure the target, implementation, and proxy admin are valid.
function upgradeAndCall(
function upgradeToAndCall(
IProxyAdmin _proxyAdmin,
address _target,
address _implementation,
......@@ -751,15 +836,20 @@ contract OPContractsManager is ISemver {
)
internal
{
assertValidContractAddress(address(_proxyAdmin));
assertValidContractAddress(_target);
assertValidContractAddress(_implementation);
_proxyAdmin.upgradeAndCall(payable(address(_target)), _implementation, _data);
}
/// @notice Updates the implementation of a proxy without calling the initializer.
/// First performs safety checks to ensure the target, implementation, and proxy admin are valid.
function upgradeTo(IProxyAdmin _proxyAdmin, address _target, address _implementation) internal {
assertValidContractAddress(_implementation);
_proxyAdmin.upgrade(payable(address(_target)), _implementation);
}
function assertValidContractAddress(address _who) internal view {
if (_who == address(0)) revert AddressNotFound(_who);
if (_who.code.length == 0) revert AddressHasNoCode(_who);
}
......@@ -772,4 +862,16 @@ contract OPContractsManager is ISemver {
function implementations() public view returns (Implementations memory) {
return implementation;
}
/// @notice Returns the implementation contract address for a given game type.
function getGameImplementation(
IDisputeGameFactory _disputeGameFactory,
GameType _gameType
)
internal
view
returns (IDisputeGame)
{
return _disputeGameFactory.gameImpls(_gameType);
}
}
......@@ -12,6 +12,11 @@ import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol";
contract OPContractsManagerInterop is OPContractsManager {
/// @custom:semver +interop-beta.1
function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop-beta.1");
}
constructor(
ISuperchainConfig _superchainConfig,
IProtocolVersions _protocolVersions,
......
......@@ -129,9 +129,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver {
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/// @notice Semantic version.
/// @custom:semver 2.3.0-beta.11
/// @custom:semver 2.3.0-beta.12
function version() public pure virtual returns (string memory) {
return "2.3.0-beta.11";
return "2.3.0-beta.12";
}
/// @notice Constructs the SystemConfig contract.
......@@ -217,22 +217,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver {
}
/// @notice Getter for the L1CrossDomainMessenger address.
function l1CrossDomainMessenger() external view returns (address addr_) {
function l1CrossDomainMessenger() public view returns (address addr_) {
addr_ = Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT);
}
/// @notice Getter for the L1ERC721Bridge address.
function l1ERC721Bridge() external view returns (address addr_) {
function l1ERC721Bridge() public view returns (address addr_) {
addr_ = Storage.getAddress(L1_ERC_721_BRIDGE_SLOT);
}
/// @notice Getter for the L1StandardBridge address.
function l1StandardBridge() external view returns (address addr_) {
function l1StandardBridge() public view returns (address addr_) {
addr_ = Storage.getAddress(L1_STANDARD_BRIDGE_SLOT);
}
/// @notice Getter for the DisputeGameFactory address.
function disputeGameFactory() external view returns (address addr_) {
function disputeGameFactory() public view returns (address addr_) {
addr_ = Storage.getAddress(DISPUTE_GAME_FACTORY_SLOT);
}
......@@ -242,10 +242,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver {
}
/// @notice Getter for the OptimismMintableERC20Factory address.
function optimismMintableERC20Factory() external view returns (address addr_) {
function optimismMintableERC20Factory() public view returns (address addr_) {
addr_ = Storage.getAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT);
}
/// @notice Consolidated getter for the Addresses struct.
function getAddresses() external view returns (Addresses memory) {
return Addresses({
l1CrossDomainMessenger: l1CrossDomainMessenger(),
l1ERC721Bridge: l1ERC721Bridge(),
l1StandardBridge: l1StandardBridge(),
disputeGameFactory: disputeGameFactory(),
optimismPortal: optimismPortal(),
optimismMintableERC20Factory: optimismMintableERC20Factory()
});
}
/// @notice Getter for the BatchInbox address.
function batchInbox() external view returns (address addr_) {
addr_ = Storage.getAddress(BATCH_INBOX_SLOT);
......
......@@ -65,9 +65,9 @@ contract SystemConfigInterop is SystemConfig {
Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager);
}
/// @custom:semver +interop-beta.10
/// @custom:semver +interop-beta.11
function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop-beta.10");
return string.concat(super.version(), "+interop-beta.11");
}
/// @notice Adds a chain to the interop dependency set. Can only be called by the dependency manager.
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
// Testing
import { Test, stdStorage, StdStorage } from "forge-std/Test.sol";
import { CommonTest } from "test/setup/CommonTest.sol";
import { DeployOPChain_TestBase } from "test/opcm/DeployOPChain.t.sol";
import { DelegateCaller } from "test/mocks/Callers.sol";
// Scripts
import { DeployOPChainInput } from "scripts/deploy/DeployOPChain.s.sol";
import { DeployOPChain_TestBase } from "test/opcm/DeployOPChain.t.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
// Libraries
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol";
// Interfaces
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
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";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
// Contracts
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
......@@ -167,6 +181,120 @@ contract OPContractsManager_InternalMethods_Test is Test {
}
}
contract OPContractsManager_Upgrade_Harness is CommonTest {
// The Upgraded event emitted by the Proxy contract.
event Upgraded(address indexed implementation);
// The Upgraded event emitted by the OPContractsManager contract.
event Upgraded(uint256 indexed l2ChainId, ISystemConfig indexed systemConfig, address indexed upgrader);
// The AddressSet event emitted by the AddressManager contract.
event AddressSet(string indexed name, address newAddress, address oldAddress);
uint256 l2ChainId;
IProxyAdmin proxyAdmin;
address upgrader;
OPContractsManager.OpChain[] opChains;
function setUp() public virtual override {
super.disableUpgradedFork();
super.setUp();
if (!isForkTest()) {
// This test is only supported in forked tests, as we are testing the upgrade.
vm.skip(true);
}
proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig)));
upgrader = proxyAdmin.owner();
vm.label(upgrader, "ProxyAdmin Owner");
opChains.push(OPContractsManager.OpChain({ systemConfigProxy: systemConfig, proxyAdmin: proxyAdmin }));
// Retrieve the l2ChainId, which was read from the superchain-registry, and saved in Artifacts
// encoded as an address.
l2ChainId = uint256(bytes32(bytes20(address(artifacts.mustGetAddress("L2ChainId")))) >> 96);
delayedWETHPermissionedGameProxy =
IDelayedWETH(payable(artifacts.mustGetAddress("PermissionedDelayedWETHProxy")));
delayedWeth = IDelayedWETH(payable(artifacts.mustGetAddress("PermissionlessDelayedWETHProxy")));
permissionedDisputeGame = IPermissionedDisputeGame(address(artifacts.mustGetAddress("PermissionedDisputeGame")));
faultDisputeGame = IFaultDisputeGame(address(artifacts.mustGetAddress("FaultDisputeGame")));
}
}
contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
function test_upgrade_succeeds() public {
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
OPContractsManager.Implementations memory impls = opcm.implementations();
address oldL1CrossDomainMessenger = addressManager.getAddress("OVM_L1CrossDomainMessenger");
expectEmitUpgraded(impls.systemConfigImpl, address(systemConfig));
vm.expectEmit(address(addressManager));
emit AddressSet("OVM_L1CrossDomainMessenger", impls.l1CrossDomainMessengerImpl, oldL1CrossDomainMessenger);
// This is where we would emit an event for the L1StandardBridge however
// the Chugsplash proxy does not emit such an event.
expectEmitUpgraded(impls.l1ERC721BridgeImpl, address(l1ERC721Bridge));
expectEmitUpgraded(impls.disputeGameFactoryImpl, address(disputeGameFactory));
expectEmitUpgraded(impls.optimismPortalImpl, address(optimismPortal2));
expectEmitUpgraded(impls.optimismMintableERC20FactoryImpl, address(l1OptimismMintableERC20Factory));
expectEmitUpgraded(impls.anchorStateRegistryImpl, address(anchorStateRegistry));
expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWETHPermissionedGameProxy));
if (address(delayedWeth) != address(0)) {
expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWeth));
}
vm.expectEmit(true, true, true, true, address(upgrader));
emit Upgraded(l2ChainId, opChains[0].systemConfigProxy, address(upgrader));
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains)));
assertEq(impls.systemConfigImpl, EIP1967Helper.getImplementation(address(systemConfig)));
assertEq(impls.l1ERC721BridgeImpl, EIP1967Helper.getImplementation(address(l1ERC721Bridge)));
assertEq(impls.disputeGameFactoryImpl, EIP1967Helper.getImplementation(address(disputeGameFactory)));
assertEq(impls.optimismPortalImpl, EIP1967Helper.getImplementation(address(optimismPortal2)));
assertEq(
impls.optimismMintableERC20FactoryImpl,
EIP1967Helper.getImplementation(address(l1OptimismMintableERC20Factory))
);
assertEq(impls.l1StandardBridgeImpl, EIP1967Helper.getImplementation(address(l1StandardBridge)));
assertEq(impls.l1CrossDomainMessengerImpl, addressManager.getAddress("OVM_L1CrossDomainMessenger"));
assertEq(impls.anchorStateRegistryImpl, EIP1967Helper.getImplementation(address(anchorStateRegistry)));
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth)));
if (address(delayedWeth) != address(0)) {
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth)));
}
// TODO: ensure dispute games are updated (upcoming PR)
}
function expectEmitUpgraded(address impl, address proxy) public {
vm.expectEmit(proxy);
emit Upgraded(impl);
}
}
contract OPContractsManager_Upgrade_TestFails is OPContractsManager_Upgrade_Harness {
function test_upgrade_notDelegateCalled_reverts() public {
vm.prank(upgrader);
vm.expectRevert(OPContractsManager.OnlyDelegatecall.selector);
opcm.upgrade(opChains);
}
function test_upgrade_superchainConfigMismatch_reverts() public {
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
// Set the superchainConfig to a different address in the OptimismPortal2 contract.
vm.store(
address(optimismPortal2),
bytes32(ForgeArtifacts.getSlot("OptimismPortal2", "superchainConfig").slot),
bytes32(abi.encode(bob))
);
vm.expectRevert(
abi.encodeWithSelector(OPContractsManager.SuperchainConfigMismatch.selector, address(systemConfig))
);
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains)));
}
}
contract OPContractsManager_AddGameType_Test is Test {
OPContractsManager internal opcm;
......
......@@ -99,13 +99,21 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init {
uint256 cfgStartBlock = deploy.cfg().systemConfigStartBlock();
assertEq(systemConfig.startBlock(), (cfgStartBlock == 0 ? block.number : cfgStartBlock));
assertEq(address(systemConfig.batchInbox()), address(batchInbox));
// Check addresses
// Check address getters both for the single contract getter and the struct getter
ISystemConfig.Addresses memory addrs = systemConfig.getAddresses();
assertEq(address(systemConfig.l1CrossDomainMessenger()), address(l1CrossDomainMessenger));
assertEq(addrs.l1CrossDomainMessenger, address(l1CrossDomainMessenger));
assertEq(address(systemConfig.l1ERC721Bridge()), address(l1ERC721Bridge));
assertEq(addrs.l1ERC721Bridge, address(l1ERC721Bridge));
assertEq(address(systemConfig.l1StandardBridge()), address(l1StandardBridge));
assertEq(addrs.l1StandardBridge, address(l1StandardBridge));
assertEq(address(systemConfig.disputeGameFactory()), address(disputeGameFactory));
assertEq(addrs.disputeGameFactory, address(disputeGameFactory));
assertEq(address(systemConfig.optimismPortal()), address(optimismPortal2));
assertEq(addrs.optimismPortal, address(optimismPortal2));
assertEq(address(systemConfig.optimismMintableERC20Factory()), address(optimismMintableERC20Factory));
assertEq(addrs.optimismMintableERC20Factory, address(optimismMintableERC20Factory));
}
}
......@@ -281,8 +289,6 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init {
)
internal
{
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Init_ResourceConfig: initialize() interface differs from mainnet.");
// Wipe out the initialized slot so the proxy can be initialized again
vm.store(address(systemConfig), bytes32(0), bytes32(0));
// Fetch the current gas limit
......@@ -325,16 +331,12 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @notice Ensures that `setGasConfig` reverts if version byte is set.
function test_setGasConfig_badValues_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'scalar exceeds max' check DNE on op mainnet");
vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: scalar exceeds max.");
systemConfig.setGasConfig({ _overhead: 0, _scalar: type(uint256).max });
}
function test_setGasConfigEcotone_notOwner_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setGasConfigEcotone' method DNE on op mainnet");
vm.expectRevert("Ownable: caller is not the owner");
systemConfig.setGasConfigEcotone({ _basefeeScalar: 0, _blobbasefeeScalar: 0 });
}
......@@ -369,16 +371,12 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` reverts if the caller is not the owner.
function test_setEIP1559Params_notOwner_reverts(uint32 _denominator, uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
vm.expectRevert("Ownable: caller is not the owner");
systemConfig.setEIP1559Params({ _denominator: _denominator, _elasticity: _elasticity });
}
/// @dev Tests that `setEIP1559Params` reverts if the denominator is zero.
function test_setEIP1559Params_zeroDenominator_reverts(uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: denominator must be >= 1");
systemConfig.setEIP1559Params({ _denominator: 0, _elasticity: _elasticity });
......@@ -386,8 +384,6 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` reverts if the elasticity is zero.
function test_setEIP1559Params_zeroElasticity_reverts(uint32 _denominator) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
_denominator = uint32(bound(_denominator, 1, type(uint32).max));
vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: elasticity must be >= 1");
......@@ -420,8 +416,6 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
}
function testFuzz_setGasConfigEcotone_succeeds(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setGasConfigEcotone' method DNE on op mainnet");
bytes32 encoded =
ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });
......@@ -465,8 +459,6 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` updates the EIP1559 parameters successfully.
function testFuzz_setEIP1559Params_succeeds(uint32 _denominator, uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
_denominator = uint32(bound(_denominator, 2, type(uint32).max));
_elasticity = uint32(bound(_elasticity, 2, type(uint32).max));
......
......@@ -29,3 +29,24 @@ contract Reverter {
revert();
}
}
/// @dev Can be etched in to any address to test making a delegatecall from that address.
contract DelegateCaller {
function dcForward(address _target, bytes memory _data) external {
assembly {
// Perform the delegatecall, make sure to pass all available gas.
let success := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0x0, 0x0)
// Copy returndata into memory at 0x0....returndatasize. Note that this *will*
// overwrite the calldata that we just copied into memory but that doesn't really
// matter because we'll be returning in a second anyway.
returndatacopy(0x0, 0x0, returndatasize())
// Success == 0 means a revert. We'll revert too and pass the data up.
if iszero(success) { revert(0x0, returndatasize()) }
// Otherwise we'll just return and pass the data up.
return(0x0, returndatasize())
}
}
}
......@@ -37,6 +37,12 @@ contract CommonTest is Test, Setup, Events {
address customGasToken;
bool useInteropOverride;
/// @dev This value is only used in forked tests. During forked tests, the default is to perform the upgrade before
/// running the tests.
/// This value should only be set to false in forked tests which are specifically testing the upgrade path
/// itself, rather than simply ensuring that the tests pass after the upgrade.
bool useUpgradedFork = true;
ERC20 L1Token;
ERC20 BadL1Token;
IOptimismMintableERC20Full L2Token;
......@@ -65,6 +71,9 @@ contract CommonTest is Test, Setup, Events {
if (useInteropOverride) {
deploy.cfg().setUseInterop(true);
}
if (useUpgradedFork) {
deploy.cfg().setUseUpgradedFork(true);
}
if (isForkTest()) {
// Skip any test suite which uses a nonstandard configuration.
......@@ -166,34 +175,42 @@ contract CommonTest is Test, Setup, Events {
emit TransactionDeposited(_from, _to, 0, abi.encodePacked(_mint, _value, _gasLimit, _isCreation, _data));
}
function enableAltDA() public {
// Check if the system has already been deployed, based off of the heuristic that alice and bob have not been
// set by the `setUp` function yet.
if (!(alice == address(0) && bob == address(0))) {
revert("CommonTest: Cannot enable altda after deployment. Consider overriding `setUp`.");
/// @dev Checks if the system has already been deployed, based off of the heuristic that alice and bob have not been
/// set by the `setUp` function yet.
function _checkNotDeployed(string memory _feature) internal view {
if (alice != address(0) && bob != address(0)) {
revert(
string.concat("CommonTest: Cannot enable ", _feature, " after deployment. Consider overriding `setUp`.")
);
}
console.log("CommonTest: enabling", _feature);
}
/// @dev Enables alternative data availability mode for testing
function enableAltDA() public {
_checkNotDeployed("altda");
useAltDAOverride = true;
}
/// @dev Sets a custom gas token for testing. Cannot be ETH.
function enableCustomGasToken(address _token) public {
// Check if the system has already been deployed, based off of the heuristic that alice and bob have not been
// set by the `setUp` function yet.
if (!(alice == address(0) && bob == address(0))) {
revert("CommonTest: Cannot enable custom gas token after deployment. Consider overriding `setUp`.");
}
_checkNotDeployed("custom gas token");
require(_token != Constants.ETHER, "CommonTest: Cannot set gas token to ETHER");
customGasToken = _token;
}
/// @dev Enables interoperability mode for testing
function enableInterop() public {
// Check if the system has already been deployed, based off of the heuristic that alice and bob have not been
// set by the `setUp` function yet.
if (!(alice == address(0) && bob == address(0))) {
revert("CommonTest: Cannot enable interop after deployment. Consider overriding `setUp`.");
_checkNotDeployed("interop");
useInteropOverride = true;
}
useInteropOverride = true;
/// @dev Disables upgrade mode for testing. By default the fork testing env will be upgraded to the latest
/// implementation. This can be used to disable the upgrade which, is useful for tests targeting the upgrade
/// process itself.
function disableUpgradedFork() public {
_checkNotDeployed("non-upgraded fork");
useUpgradedFork = false;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { console2 as console } from "forge-std/console2.sol";
// Testing
import { stdJson } from "forge-std/StdJson.sol";
import { stdToml } from "forge-std/StdToml.sol";
import { DelegateCaller } from "test/mocks/Callers.sol";
// Scripts
import { Deployer } from "scripts/deploy/Deployer.sol";
......@@ -16,6 +19,9 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
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 { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
/// @title ForkLive
/// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an
......@@ -27,7 +33,7 @@ import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
/// superchain-registry.
/// This contract must not have constructor logic because it is set into state using `etch`.
contract ForkLive is Deployer {
using stdJson for string;
using stdToml for string;
/// @notice Returns the base chain name to use for forking
/// @return The base chain name as a string
......@@ -52,6 +58,12 @@ contract ForkLive is Deployer {
// Now deploy the updated OPCM and implementations of the contracts
_deployNewImplementations();
// Now upgrade the contracts (if the config is set to do so)
if (cfg.useUpgradedFork()) {
console.log("ForkLive: upgrading");
_upgrade();
}
}
/// @notice Reads the superchain config files and saves the addresses to disk.
......@@ -67,6 +79,8 @@ contract ForkLive is Deployer {
string memory superchainToml = vm.readFile(string.concat(superchainBasePath, baseChain(), "/superchain.toml"));
string memory opToml = vm.readFile(string.concat(superchainBasePath, baseChain(), "/", opChain(), ".toml"));
// Slightly hacky, we encode the uint chainId as an address to save it in Artifacts
artifacts.save("L2ChainId", address(uint160(vm.parseTomlUint(opToml, ".chain_id"))));
// Superchain shared contracts
saveProxyAndImpl("SuperchainConfig", superchainToml, ".superchain_config_addr");
saveProxyAndImpl("ProtocolVersions", superchainToml, ".protocol_versions_addr");
......@@ -99,11 +113,17 @@ contract ForkLive is Deployer {
saveProxyAndImpl("DelayedWETH", opToml, ".addresses.DelayedWETHProxy");
// Fault proof non-proxied contracts
// For chains that don't have a permissionless game, we save the dispute game and WETH
// addresses as the zero address.
artifacts.save("PreimageOracle", vm.parseTomlAddress(opToml, ".addresses.PreimageOracle"));
artifacts.save("MipsSingleton", vm.parseTomlAddress(opToml, ".addresses.MIPS"));
IDisputeGameFactory disputeGameFactory =
IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy"));
artifacts.save("FaultDisputeGame", vm.parseTomlAddress(opToml, ".addresses.FaultDisputeGame"));
IFaultDisputeGame faultDisputeGame =
IFaultDisputeGame(opToml.readAddressOr(".addresses.FaultDisputeGame", address(0)));
artifacts.save("FaultDisputeGame", address(faultDisputeGame));
artifacts.save("PermissionlessDelayedWETHProxy", address(faultDisputeGame.weth()));
// The PermissionedDisputeGame and PermissionedDelayedWETHProxy are not listed in the registry for OP, so we
// look it up onchain
IFaultDisputeGame permissionedDisputeGame =
......@@ -119,6 +139,25 @@ contract ForkLive is Deployer {
deploy.deployImplementations({ _isInterop: false });
}
/// @notice Upgrades the contracts using the OPCM.
function _upgrade() internal {
OPContractsManager opcm = OPContractsManager(artifacts.mustGetAddress("OPContractsManager"));
ISystemConfig systemConfig = ISystemConfig(artifacts.mustGetAddress("SystemConfigProxy"));
IProxyAdmin proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig)));
address upgrader = proxyAdmin.owner();
vm.label(upgrader, "ProxyAdmin Owner");
OPContractsManager.OpChain[] memory opChains = new OPContractsManager.OpChain[](1);
opChains[0] = OPContractsManager.OpChain({ systemConfigProxy: systemConfig, proxyAdmin: proxyAdmin });
// TODO Migrate from DelegateCaller to a Safe to reduce risk of mocks not properly
// reflecting the production system.
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains)));
}
/// @notice Saves the proxy and implementation addresses for a contract name
/// @param _contractName The name of the contract to save
/// @param _tomlPath The path to the superchain config file
......
......@@ -20,6 +20,9 @@ import { Preinstalls } from "src/libraries/Preinstalls.sol";
import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol";
import { Chains } from "scripts/libraries/Chains.sol";
// Contracts (TODO: move to interfaces)
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
// Interfaces
import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol";
import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol";
......@@ -51,6 +54,8 @@ import { IWETH98 } from "interfaces/universal/IWETH98.sol";
import { IGovernanceToken } from "interfaces/governance/IGovernanceToken.sol";
import { ILegacyMessagePasser } from "interfaces/legacy/ILegacyMessagePasser.sol";
import { ISuperchainTokenBridge } from "interfaces/L2/ISuperchainTokenBridge.sol";
import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol";
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
/// @title Setup
/// @dev This contact is responsible for setting up the contracts in state. It currently
......@@ -83,10 +88,15 @@ contract Setup {
/// @notice Allows users of Setup to override what L2 genesis is being created.
Fork l2Fork = LATEST_FORK;
// L1 contracts
// L1 contracts - dispute
IDisputeGameFactory disputeGameFactory;
IAnchorStateRegistry anchorStateRegistry;
IFaultDisputeGame faultDisputeGame;
IDelayedWETH delayedWeth;
IPermissionedDisputeGame permissionedDisputeGame;
IDelayedWETH delayedWETHPermissionedGameProxy;
// L1 contracts - core
IOptimismPortal2 optimismPortal2;
ISystemConfig systemConfig;
IL1StandardBridge l1StandardBridge;
......@@ -97,6 +107,7 @@ contract Setup {
IProtocolVersions protocolVersions;
ISuperchainConfig superchainConfig;
IDataAvailabilityChallenge dataAvailabilityChallenge;
OPContractsManager opcm;
// L2 contracts
IL2CrossDomainMessenger l2CrossDomainMessenger =
......@@ -218,6 +229,7 @@ contract Setup {
anchorStateRegistry = IAnchorStateRegistry(artifacts.mustGetAddress("AnchorStateRegistryProxy"));
disputeGameFactory = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy"));
delayedWeth = IDelayedWETH(artifacts.mustGetAddress("DelayedWETHProxy"));
opcm = OPContractsManager(artifacts.mustGetAddress("OPContractsManager"));
if (deploy.cfg().useAltDA()) {
dataAvailabilityChallenge =
......
......@@ -391,6 +391,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "SystemConfig", _sel: _getSel("basefeeScalar()") });
_addSpec({ _name: "SystemConfig", _sel: _getSel("blobbasefeeScalar()") });
_addSpec({ _name: "SystemConfig", _sel: _getSel("maximumGasLimit()") });
_addSpec({ _name: "SystemConfig", _sel: _getSel("getAddresses()") });
// SystemConfigInterop
_addSpec({ _name: "SystemConfigInterop", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") });
......@@ -470,6 +471,7 @@ contract Specification_Test is CommonTest {
_auth: Role.DEPENDENCYMANAGER
});
_addSpec({ _name: "SystemConfigInterop", _sel: _getSel("dependencyManager()") });
_addSpec({ _name: "SystemConfigInterop", _sel: _getSel("getAddresses()") });
// ProxyAdmin
_addSpec({ _name: "ProxyAdmin", _sel: _getSel("addressManager()") });
......@@ -783,6 +785,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.blueprints.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.implementations.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.upgrade.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.addGameType.selector });
// OPContractsManagerInterop
......@@ -794,6 +797,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.blueprints.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.implementations.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.upgrade.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.addGameType.selector });
// DeputyGuardianModule
......
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