Skip to content

Commit

Permalink
feat: Front OPSM with Proxy and Initialize (#11875)
Browse files Browse the repository at this point in the history
* fix: getting stack underflow error.

* feat: adding proxy infront of OPStackManager.

* fix: PR comments, we're landing on using the initialize function over setRelease.

* fix: rename function.

* fix: nit

* fix: infering proxy admin from superchain config.

* fix: ran command: just pre-pr-no-build

* fix: nits

* fix: using CommonBase in DeployImplementations.s.sol.

* op-chain-ops: pass superchain proxy admin address as input to deployments script

---------

Co-authored-by: Matt Solomon <[email protected]>
Co-authored-by: protolambda <[email protected]>
  • Loading branch information
3 people authored Sep 14, 2024
1 parent 5e14a61 commit 6cf35da
Show file tree
Hide file tree
Showing 16 changed files with 384 additions and 243 deletions.
1 change: 1 addition & 0 deletions op-chain-ops/interopgen/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ func deploySuperchainToL1(l1Host *script.Host, superCfg *SuperchainConfig) (*Sup
Release: superCfg.Implementations.Release,
SuperchainConfigProxy: superDeployment.SuperchainConfigProxy,
ProtocolVersionsProxy: superDeployment.ProtocolVersionsProxy,
SuperchainProxyAdmin: superDeployment.SuperchainProxyAdmin,
UseInterop: superCfg.Implementations.UseInterop,
})
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions op-chain-ops/interopgen/deployers/implementations.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type DeployImplementationsInput struct {
Release string
SuperchainConfigProxy common.Address
ProtocolVersionsProxy common.Address
SuperchainProxyAdmin common.Address
UseInterop bool // if true, deploy Interop implementations
}

Expand Down
75 changes: 51 additions & 24 deletions packages/contracts-bedrock/scripts/DeployImplementations.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.15;

import { Script } from "forge-std/Script.sol";
import { CommonBase } from "forge-std/Base.sol";

import { LibString } from "@solady/utils/LibString.sol";

Expand Down Expand Up @@ -37,7 +38,7 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
import { Solarray } from "scripts/libraries/Solarray.sol";

// See DeploySuperchain.s.sol for detailed comments on the script architecture used here.
contract DeployImplementationsInput {
contract DeployImplementationsInput is CommonBase {
uint256 internal _withdrawalDelaySeconds;
uint256 internal _minProposalSizeBytes;
uint256 internal _challengePeriodSeconds;
Expand Down Expand Up @@ -130,6 +131,15 @@ contract DeployImplementationsInput {
require(address(_protocolVersionsProxy) != address(0), "DeployImplementationsInput: not set");
return _protocolVersionsProxy;
}

function superchainProxyAdmin() public returns (ProxyAdmin) {
SuperchainConfig proxy = this.superchainConfigProxy();
// Can infer the superchainProxyAdmin from the superchainConfigProxy.
vm.prank(address(0));
ProxyAdmin proxyAdmin = ProxyAdmin(Proxy(payable(address(proxy))).admin());
require(address(proxyAdmin) != address(0), "DeployImplementationsInput: not set");
return proxyAdmin;
}
}

contract DeployImplementationsOutput {
Expand Down Expand Up @@ -169,7 +179,7 @@ contract DeployImplementationsOutput {
require(false, "DeployImplementationsOutput: not implemented");
}

function checkOutput() public view {
function checkOutput() public {
address[] memory addrs = Solarray.addresses(
address(this.opsm()),
address(this.optimismPortalImpl()),
Expand All @@ -186,8 +196,9 @@ contract DeployImplementationsOutput {
DeployUtils.assertValidContractAddresses(addrs);
}

function opsm() public view returns (OPStackManager) {
function opsm() public returns (OPStackManager) {
DeployUtils.assertValidContractAddress(address(_opsm));
DeployUtils.assertImplementationSet(address(_opsm));
return _opsm;
}

Expand Down Expand Up @@ -292,24 +303,34 @@ contract DeployImplementations is Script {
});
}

// Deploy and initialize a proxied OPStackManager.
function createOPSMContract(
DeployImplementationsInput _dii,
DeployImplementationsOutput,
OPStackManager.Blueprints memory blueprints
OPStackManager.Blueprints memory blueprints,
string memory release,
OPStackManager.ImplementationSetter[] memory setters
)
internal
virtual
returns (OPStackManager opsm_)
returns (OPStackManager opsmProxy_)
{
SuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy();
ProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();
ProxyAdmin proxyAdmin = _dii.superchainProxyAdmin();

vm.broadcast(msg.sender);
opsm_ = new OPStackManager({
_superchainConfig: superchainConfigProxy,
_protocolVersions: protocolVersionsProxy,
_blueprints: blueprints
});
vm.startBroadcast(msg.sender);
Proxy proxy = new Proxy(address(msg.sender));
OPStackManager opsm = new OPStackManager(superchainConfigProxy, protocolVersionsProxy);

OPStackManager.InitializerInputs memory initializerInputs =
OPStackManager.InitializerInputs(blueprints, setters, release, true);
proxy.upgradeToAndCall(address(opsm), abi.encodeWithSelector(opsm.initialize.selector, initializerInputs));

proxy.changeAdmin(address(proxyAdmin)); // transfer ownership of Proxy contract to the ProxyAdmin contract
vm.stopBroadcast();

opsmProxy_ = OPStackManager(address(proxy));
}

function deployOPStackManager(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
Expand All @@ -329,9 +350,6 @@ contract DeployImplementations is Script {
vm.stopBroadcast();
// forgefmt: disable-end

// This call contains a broadcast to deploy OPSM.
OPStackManager opsm = createOPSMContract(_dii, _dio, blueprints);

OPStackManager.ImplementationSetter[] memory setters = new OPStackManager.ImplementationSetter[](6);
setters[0] = OPStackManager.ImplementationSetter({
name: "L1ERC721Bridge",
Expand Down Expand Up @@ -359,8 +377,8 @@ contract DeployImplementations is Script {
info: OPStackManager.Implementation(address(_dio.l1StandardBridgeImpl()), L1StandardBridge.initialize.selector)
});

vm.broadcast(msg.sender);
opsm.setRelease({ _release: release, _isLatest: true, _setters: setters });
// This call contains a broadcast to deploy OPSM which is proxied.
OPStackManager opsm = createOPSMContract(_dii, _dio, blueprints, release, setters);

vm.label(address(opsm), "OPStackManager");
_dio.set(_dio.opsm.selector, address(opsm));
Expand Down Expand Up @@ -571,21 +589,30 @@ contract DeployImplementationsInterop is DeployImplementations {
function createOPSMContract(
DeployImplementationsInput _dii,
DeployImplementationsOutput,
OPStackManager.Blueprints memory blueprints
OPStackManager.Blueprints memory blueprints,
string memory release,
OPStackManager.ImplementationSetter[] memory setters
)
internal
override
returns (OPStackManager opsm_)
returns (OPStackManager opsmProxy_)
{
SuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy();
ProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();
ProxyAdmin proxyAdmin = _dii.superchainProxyAdmin();

vm.broadcast(msg.sender);
opsm_ = new OPStackManagerInterop({
_superchainConfig: superchainConfigProxy,
_protocolVersions: protocolVersionsProxy,
_blueprints: blueprints
});
vm.startBroadcast(msg.sender);
Proxy proxy = new Proxy(address(msg.sender));
OPStackManager opsm = new OPStackManagerInterop(superchainConfigProxy, protocolVersionsProxy);

OPStackManager.InitializerInputs memory initializerInputs =
OPStackManager.InitializerInputs(blueprints, setters, release, true);
proxy.upgradeToAndCall(address(opsm), abi.encodeWithSelector(opsm.initialize.selector, initializerInputs));

proxy.changeAdmin(address(proxyAdmin)); // transfer ownership of Proxy contract to the ProxyAdmin contract
vm.stopBroadcast();

opsmProxy_ = OPStackManagerInterop(address(proxy));
}

function deployOptimismPortalImpl(
Expand Down
1 change: 1 addition & 0 deletions packages/contracts-bedrock/scripts/DeployOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ contract DeployOPChainInput {
return _l2ChainId;
}

// TODO: Check that opsm is proxied and it has an implementation.
function opsm() public view returns (OPStackManager) {
require(address(_opsm) != address(0), "DeployOPChainInput: not set");
return _opsm;
Expand Down
12 changes: 12 additions & 0 deletions packages/contracts-bedrock/scripts/libraries/DeployUtils.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { Proxy } from "src/universal/Proxy.sol";
import { LibString } from "@solady/utils/LibString.sol";
import { Vm } from "forge-std/Vm.sol";

library DeployUtils {
Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

// This takes a sender and an identifier and returns a deterministic address based on the two.
// The result is used to etch the input and output contracts to a deterministic address based on
// those two values, where the identifier represents the input or output contract, such as
Expand All @@ -18,6 +22,14 @@ library DeployUtils {
require(_who.code.length > 0, string.concat("DeployUtils: no code at ", LibString.toHexStringChecksummed(_who)));
}

function assertImplementationSet(address _proxy) internal {
// We prank as the zero address due to the Proxy's `proxyCallIfNotAdmin` modifier.
// Pranking inside this function also means it can no longer be considered `view`.
vm.prank(address(0));
address implementation = Proxy(payable(_proxy)).implementation();
assertValidContractAddress(implementation);
}

function assertValidContractAddresses(address[] memory _addrs) internal view {
// Assert that all addresses are non-zero and have code.
// We use LibString to avoid the need for adding cheatcodes to this contract.
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"sourceCodeHash": "0xde4df0f9633dc0cdb1c9f634003ea5b0f7c5c1aebc407bc1b2f44c0ecf938649"
},
"src/L1/OPStackManager.sol": {
"initCodeHash": "0xe1eab75651e3d81ad20ca01b1e7d373b25d716ee5f8841a56e56b4531a6e0e70",
"sourceCodeHash": "0x5182a2678dadb200dd255ecdfa395e5f7b1e1e27288e78ddf8802ab51ed2dd81"
"initCodeHash": "0x8081ca5dd48497b74758d1425ad6f025d6fd3cb144b4c5d4335b9a04e78b8474",
"sourceCodeHash": "0xb5fb50a9ddf8c0aee6d0e545f8ef4528f27698f3522cab744cd44ffaef6364d2"
},
"src/L1/OptimismPortal.sol": {
"initCodeHash": "0xb7a7a28d5b3b88334e7cb4bc1c5fbbf9f691d934e907a2fed6a30e461eb1c0f6",
Expand Down
Loading

0 comments on commit 6cf35da

Please sign in to comment.