Commit 027756c4 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6446 from ethereum-optimism/ctb/portal-immutables

contracts-bedrock: migrate OptimismPortal single impl
parents d003f600 9dc2386a
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 |
| l2Oracle | contract L2OutputOracle | 53 | 1 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
| systemConfig | 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));
......
......@@ -3,7 +3,7 @@
"src/L1/L1ERC721Bridge.sol": "0xac9d8e236a1b35c358f9800834f65375cf4270155e817cf3d0f2bac1968f9107",
"src/L1/L1StandardBridge.sol": "0x26fd79e041c403f4bc68758c410fcc801975e7648c0b51a2c4a6e8c44fabcbfd",
"src/L1/L2OutputOracle.sol": "0xd6c5eb38732077c4705f46a61be68a7beccc069a99ed1d07b8e1fc6e1de8ffa6",
"src/L1/OptimismPortal.sol": "0x06c324c474d251a1ef0a1a6a22013964c5b2b871e641bbedf447f231e3f44dcc",
"src/L1/OptimismPortal.sol": "0xeaa47a63e8a3bcfdb7dfd3e6c8608369e34e362d9de82f3acf13cbc27c070bf7",
"src/L1/SystemConfig.sol": "0x8e2b5103d2eb93b74af2e2f96a4505e637cdc3c44d80cf5ec2eca70060e1deff",
"src/L2/BaseFeeVault.sol": "0xa596e60762f16192cfa86459fcb9f4da9d8f756106eedac643a1ffeafbbfcc5f",
"src/L2/GasPriceOracle.sol": "0xc735a8bf01ad8bca194345748537bfd9924909c0342bc133c4a31e2fb8cb9882",
......
......@@ -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,18 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// This may be removed in the future.
bool public paused;
/// @notice Address of the L2OutputOracle contract.
/// @custom:network-specific
L2OutputOracle public l2Oracle;
/// @notice Address of the SystemConfig contract.
/// @custom:network-specific
SystemConfig public systemConfig;
/// @notice Address that has the ability to pause and unpause withdrawals.
/// @custom:network-specific
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.
......@@ -103,41 +106,64 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
_;
}
/// @custom:semver 1.7.2
/// @custom:semver 1.8.0
/// @notice Constructs the OptimismPortal contract.
constructor() Semver(1, 8, 0) {
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(
/// @param _systemConfig Address of the SystemConfig contract.
function initialize(
L2OutputOracle _l2Oracle,
address _guardian,
bool _paused,
SystemConfig _config
) Semver(1, 7, 2) {
L2_ORACLE = _l2Oracle;
GUARDIAN = _guardian;
SYSTEM_CONFIG = _config;
initialize(_paused);
}
/// @notice Initializer.
function initialize(bool _paused) public initializer {
SystemConfig _systemConfig,
bool _paused
) public reinitializer(2) {
l2Sender = Constants.DEFAULT_L2_SENDER;
l2Oracle = _l2Oracle;
systemConfig = _systemConfig;
guardian = _guardian;
paused = _paused;
__ResourceMetering_init();
}
/// @notice Getter for the L2OutputOracle
/// @custom:legacy
function L2_ORACLE() external view returns (L2OutputOracle) {
return l2Oracle;
}
/// @notice Getter for the SystemConfig
/// @custom:legacy
function SYSTEM_CONFIG() external view returns (SystemConfig) {
return systemConfig;
}
/// @notice Getter for the Guardian
/// @custom:legacy
function GUARDIAN() external view returns (address) {
return guardian;
}
/// @notice Pauses withdrawals.
function pause() external {
require(msg.sender == GUARDIAN, "OptimismPortal: only guardian can pause");
require(msg.sender == guardian, "OptimismPortal: only guardian can pause");
paused = true;
emit Paused(msg.sender);
}
/// @notice Unpauses withdrawals.
function unpause() external {
require(msg.sender == GUARDIAN, "OptimismPortal: only guardian can unpause");
require(msg.sender == guardian, "OptimismPortal: only guardian can unpause");
paused = false;
emit Unpaused(msg.sender);
}
......@@ -179,7 +205,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
override
returns (ResourceMetering.ResourceConfig memory)
{
return SYSTEM_CONFIG.resourceConfig();
return systemConfig.resourceConfig();
}
/// @notice Proves a withdrawal transaction.
......@@ -203,7 +229,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// Get the output root and load onto the stack to prevent multiple mloads. This will
// revert if there is no output root for the given block number.
bytes32 outputRoot = L2_ORACLE.getL2Output(_l2OutputIndex).outputRoot;
bytes32 outputRoot = l2Oracle.getL2Output(_l2OutputIndex).outputRoot;
// Verify that the output root can be generated with the elements in the proof.
require(
......@@ -223,7 +249,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// output index has been updated.
require(
provenWithdrawal.timestamp == 0 ||
L2_ORACLE.getL2Output(provenWithdrawal.l2OutputIndex).outputRoot !=
l2Oracle.getL2Output(provenWithdrawal.l2OutputIndex).outputRoot !=
provenWithdrawal.outputRoot,
"OptimismPortal: withdrawal hash has already been proven"
);
......@@ -295,7 +321,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// starting timestamp inside the L2OutputOracle. Not strictly necessary but extra layer of
// safety against weird bugs in the proving step.
require(
provenWithdrawal.timestamp >= L2_ORACLE.startingTimestamp(),
provenWithdrawal.timestamp >= l2Oracle.startingTimestamp(),
"OptimismPortal: withdrawal timestamp less than L2 Oracle starting timestamp"
);
......@@ -310,9 +336,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// Grab the OutputProposal from the L2OutputOracle, will revert if the output that
// corresponds to the given index has not been proposed yet.
Types.OutputProposal memory proposal = L2_ORACLE.getL2Output(
provenWithdrawal.l2OutputIndex
);
Types.OutputProposal memory proposal = l2Oracle.getL2Output(provenWithdrawal.l2OutputIndex);
// Check that the output root that was used to prove the withdrawal is the same as the
// current output root for the given output index. An output root may change if it is
......@@ -430,7 +454,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// @param _l2OutputIndex Index of the L2 output to check.
/// @return Whether or not the output is finalized.
function isOutputFinalized(uint256 _l2OutputIndex) external view returns (bool) {
return _isFinalizationPeriodElapsed(L2_ORACLE.getL2Output(_l2OutputIndex).timestamp);
return _isFinalizationPeriodElapsed(l2Oracle.getL2Output(_l2OutputIndex).timestamp);
}
/// @notice Determines whether the finalization period has elapsed with respect to
......@@ -438,6 +462,6 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// @param _timestamp Timestamp to check.
/// @return Whether or not the finalization period has elapsed.
function _isFinalizationPeriodElapsed(uint256 _timestamp) internal view returns (bool) {
return block.timestamp > _timestamp + L2_ORACLE.FINALIZATION_PERIOD_SECONDS();
return block.timestamp > _timestamp + l2Oracle.FINALIZATION_PERIOD_SECONDS();
}
}
......@@ -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";
......@@ -25,6 +26,9 @@ contract OptimismPortal_Test is Portal_Initializer {
/// @dev Tests that the constructor sets the correct values.
function test_constructor_succeeds() external {
assertEq(address(op.L2_ORACLE()), address(oracle));
assertEq(address(op.l2Oracle()), address(oracle));
assertEq(op.GUARDIAN(), guardian);
assertEq(op.guardian(), guardian);
assertEq(op.l2Sender(), 0x000000000000000000000000000000000000dEaD);
assertEq(op.paused(), false);
}
......@@ -1121,13 +1125,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 +1152,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