Commit 716aa394 authored by Mark Tyneway's avatar Mark Tyneway

contracts-bedrock: migrate OptimismPortal single impl

Migrate the network specific config in the `OptimismPortal`
from being `immutable` values into storage. This allows for
a single implementation to be used for all proxies in the
network.

As seen in the storage layout, no storage values are modified.
Only new storage values are added. This is very important for
ensuring the integrity of storage in the contract.

The deployment complexity is reduced by removing all constructor
values and setting all config in the `initialize` function.
The sentinel contract should use all null values for its fields
so that it is not confused as the contract for an actual network.

The bindings are regnerated. A follow up commit will bump the
minor semver version in the `OptimismPortal`
parent 747876d0
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
......@@ -63,6 +63,9 @@
| finalizedWithdrawals | mapping(bytes32 => bool) | 51 | 0 | 32 | src/L1/OptimismPortal.sol:OptimismPortal |
| provenWithdrawals | mapping(bytes32 => struct OptimismPortal.ProvenWithdrawal) | 52 | 0 | 32 | src/L1/OptimismPortal.sol:OptimismPortal |
| paused | bool | 53 | 0 | 1 | src/L1/OptimismPortal.sol:OptimismPortal |
| L2_ORACLE | contract L2OutputOracle | 53 | 1 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
| SYSTEM_CONFIG | contract SystemConfig | 54 | 0 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
| GUARDIAN | address | 55 | 0 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
=======================
➡ src/L1/SystemConfig.sol:SystemConfig
......
......@@ -292,24 +292,11 @@ contract Deploy is Deployer {
/// @notice Deploy the OptimismPortal
function deployOptimismPortal() broadcast() public returns (address) {
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address guardian = cfg.portalGuardian();
if (guardian.code.length == 0) {
console.log("Portal guardian has no code: %s", guardian);
}
OptimismPortal portal = new OptimismPortal();
OptimismPortal portal = new OptimismPortal({
_l2Oracle: L2OutputOracle(l2OutputOracleProxy),
_guardian: guardian,
_paused: true,
_config: SystemConfig(systemConfigProxy)
});
require(address(portal.L2_ORACLE()) == l2OutputOracleProxy);
require(portal.GUARDIAN() == guardian);
require(address(portal.SYSTEM_CONFIG()) == systemConfigProxy);
require(address(portal.L2_ORACLE()) == address(0));
require(portal.GUARDIAN() == address(0));
require(address(portal.SYSTEM_CONFIG()) == address(0));
require(portal.paused() == true);
save("OptimismPortal", address(portal));
......@@ -681,10 +668,23 @@ contract Deploy is Deployer {
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address guardian = cfg.portalGuardian();
if (guardian.code.length == 0) {
console.log("Portal guardian has no code: %s", guardian);
}
proxyAdmin.upgradeAndCall({
_proxy: payable(optimismPortalProxy),
_implementation: optimismPortal,
_data: abi.encodeCall(OptimismPortal.initialize, (false))
_data: abi.encodeCall(
OptimismPortal.initialize,
(
L2OutputOracle(l2OutputOracleProxy),
guardian,
SystemConfig(systemConfigProxy),
false
)
)
});
OptimismPortal portal = OptimismPortal(payable(optimismPortalProxy));
......
......@@ -35,15 +35,6 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// @notice The L2 gas limit set when eth is deposited using the receive() function.
uint64 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000;
/// @notice Address of the L2OutputOracle contract.
L2OutputOracle public immutable L2_ORACLE;
/// @notice Address of the SystemConfig contract.
SystemConfig public immutable SYSTEM_CONFIG;
/// @notice Address that has the ability to pause and unpause withdrawals.
address public immutable GUARDIAN;
/// @notice Address of the L2 account which initiated a withdrawal in this transaction.
/// If the of this variable is the default L2 sender address, then we are NOT inside of
/// a call to finalizeWithdrawalTransaction.
......@@ -60,6 +51,15 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// This may be removed in the future.
bool public paused;
/// @notice Address of the L2OutputOracle contract.
L2OutputOracle public L2_ORACLE;
/// @notice Address of the SystemConfig contract.
SystemConfig public SYSTEM_CONFIG;
/// @notice Address that has the ability to pause and unpause withdrawals.
address public GUARDIAN;
/// @notice Emitted when a transaction is deposited from L1 to L2.
/// The parameters of this event are read by the rollup node and used to derive deposit
/// transactions on L2.
......@@ -105,25 +105,25 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// @custom:semver 1.7.2
/// @notice Constructs the OptimismPortal contract.
constructor() Semver(1, 7, 2) {
initialize({
_l2Oracle: L2OutputOracle(address(0)),
_guardian: address(0),
_systemConfig: SystemConfig(address(0)),
_paused: true
});
}
/// @notice Initializer.
/// @param _l2Oracle Address of the L2OutputOracle contract.
/// @param _guardian Address that can pause withdrawals.
/// @param _paused Sets the contract's pausability state.
/// @param _config Address of the SystemConfig contract.
constructor(
L2OutputOracle _l2Oracle,
address _guardian,
bool _paused,
SystemConfig _config
) Semver(1, 7, 2) {
/// @param _systemConfig Address of the SystemConfig contract.
function initialize(L2OutputOracle _l2Oracle, address _guardian, SystemConfig _systemConfig, bool _paused) public reinitializer(2) {
l2Sender = Constants.DEFAULT_L2_SENDER;
L2_ORACLE = _l2Oracle;
SYSTEM_CONFIG = _systemConfig;
GUARDIAN = _guardian;
SYSTEM_CONFIG = _config;
initialize(_paused);
}
/// @notice Initializer.
function initialize(bool _paused) public initializer {
l2Sender = Constants.DEFAULT_L2_SENDER;
paused = _paused;
__ResourceMetering_init();
}
......
......@@ -207,18 +207,16 @@ contract Portal_Initializer is L2OutputOracle_Initializer {
_config: config
});
opImpl = new OptimismPortal({
_l2Oracle: oracle,
_guardian: guardian,
_paused: true,
_config: systemConfig
});
opImpl = new OptimismPortal();
Proxy proxy = new Proxy(multisig);
vm.prank(multisig);
proxy.upgradeToAndCall(
address(opImpl),
abi.encodeWithSelector(OptimismPortal.initialize.selector, false)
abi.encodeCall(
OptimismPortal.initialize,
(oracle, guardian, systemConfig, false)
)
);
op = OptimismPortal(payable(address(proxy)));
vm.label(address(op), "OptimismPortal");
......@@ -726,7 +724,7 @@ contract NextImpl is Initializable {
bytes32 slot21;
bytes32 public constant slot21Init = bytes32(hex"1337");
function initialize() public reinitializer(2) {
function initialize(uint8 _init) public reinitializer(_init) {
// Slot21 is unused by an of our upgradeable contracts.
// This is used to verify that we can access this value after an upgrade.
slot21 = slot21Init;
......
......@@ -454,7 +454,7 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer {
vm.startPrank(multisig);
proxy.upgradeToAndCall(
address(nextImpl),
abi.encodeWithSelector(NextImpl.initialize.selector)
abi.encodeWithSelector(NextImpl.initialize.selector, 2)
);
assertEq(proxy.implementation(), address(nextImpl));
......
......@@ -14,6 +14,7 @@ import { Proxy } from "../src/universal/Proxy.sol";
import { ResourceMetering } from "../src/L1/ResourceMetering.sol";
import { AddressAliasHelper } from "../src/vendor/AddressAliasHelper.sol";
import { L2OutputOracle } from "../src/L1/L2OutputOracle.sol";
import { SystemConfig } from "../src/L1/SystemConfig.sol";
// Target contract
import { OptimismPortal } from "../src/L1/OptimismPortal.sol";
......@@ -1121,13 +1122,23 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
/// @dev Tests that the proxy cannot be initialized twice.
function test_initialize_cannotInitProxy_reverts() external {
vm.expectRevert("Initializable: contract is already initialized");
OptimismPortal(payable(proxy)).initialize(false);
OptimismPortal(payable(proxy)).initialize({
_l2Oracle: L2OutputOracle(address(0)),
_systemConfig: SystemConfig(address(0)),
_guardian: address(0),
_paused: false
});
}
/// @dev Tests that the implementation cannot be initialized twice.
function test_initialize_cannotInitImpl_reverts() external {
vm.expectRevert("Initializable: contract is already initialized");
OptimismPortal(opImpl).initialize(false);
OptimismPortal(opImpl).initialize({
_l2Oracle: L2OutputOracle(address(0)),
_systemConfig: SystemConfig(address(0)),
_guardian: address(0),
_paused: false
});
}
/// @dev Tests that the proxy can be upgraded.
......@@ -1138,9 +1149,11 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
NextImpl nextImpl = new NextImpl();
vm.startPrank(multisig);
// The value passed to the initialize must be larger than the last value
// that initialize was called with.
proxy.upgradeToAndCall(
address(nextImpl),
abi.encodeWithSelector(NextImpl.initialize.selector)
abi.encodeWithSelector(NextImpl.initialize.selector, 3)
);
assertEq(proxy.implementation(), address(nextImpl));
......
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