Skip to content

Commit

Permalink
feature(op-node): add DeployUpgrades.s.sol
Browse files Browse the repository at this point in the history
  • Loading branch information
redhdx committed Sep 13, 2024
1 parent afbb8b1 commit a3277e8
Show file tree
Hide file tree
Showing 3 changed files with 375 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/contracts-bedrock/scripts/Chains.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ library Chains {
uint256 internal constant GethDevnet = 1337;
uint256 internal constant Hardhat = 31337;
uint256 internal constant BscDevnet = 714;
uint256 internal constant BscTestnet = 97;
uint256 internal constant BscMainnet = 56;
// TODO update for test
uint256 internal constant BscQAnet = 1;
}
363 changes: 363 additions & 0 deletions packages/contracts-bedrock/scripts/DeployUpgrades.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,363 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { VmSafe } from "forge-std/Vm.sol";
import { Script } from "forge-std/Script.sol";

import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.sol";

import { Deployer } from "scripts/Deployer.sol";

import { Proxy } from "src/universal/Proxy.sol";
import { L1StandardBridge } from "src/L1/L1StandardBridge.sol";
import { StandardBridge } from "src/universal/StandardBridge.sol";
import { OptimismPortal } from "src/L1/OptimismPortal.sol";
import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol";
import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol";
import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
import { SystemConfig } from "src/L1/SystemConfig.sol";
import { ResourceMetering } from "src/L1/ResourceMetering.sol";
import { Constants } from "src/libraries/Constants.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
import { ProtocolVersions, ProtocolVersion } from "src/L1/ProtocolVersions.sol";
import { StorageSetter } from "src/universal/StorageSetter.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Chains } from "scripts/Chains.sol";
import { Config } from "scripts/Config.sol";

import { ChainAssertions } from "scripts/ChainAssertions.sol";
import { Types } from "scripts/Types.sol";
import { LibStateDiff } from "scripts/libraries/LibStateDiff.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { ForgeArtifacts } from "scripts/ForgeArtifacts.sol";
import { Process } from "scripts/libraries/Process.sol";

/// @title Deploy
/// @notice Script used to deploy a bedrock system. The entire system is deployed within the `run` function.
/// To add a new contract to the system, add a public function that deploys that individual contract.
/// Then add a call to that function inside of `run`. Be sure to call the `save` function after each
/// deployment so that hardhat-deploy style artifacts can be generated using a call to `sync()`.
/// The `CONTRACT_ADDRESSES_PATH` environment variable can be set to a path that contains a JSON file full of
/// contract name to address pairs. That enables this script to be much more flexible in the way it is used.
/// This contract must not have constructor logic because it is set into state using `etch`.
contract Deploy is Deployer {
using stdJson for string;

////////////////////////////////////////////////////////////////
// Modifiers //
////////////////////////////////////////////////////////////////

/// @notice Modifier that wraps a function in broadcasting.
modifier broadcast() {
vm.startBroadcast(msg.sender);
_;
vm.stopBroadcast();
}

////////////////////////////////////////////////////////////////
// Accessors //
////////////////////////////////////////////////////////////////

/// @notice The create2 salt used for deployment of the contract implementations.
/// Using this helps to reduce config across networks as the implementation
/// addresses will be the same across networks when deployed with create2.
function _implSalt() internal view returns (bytes32) {
return keccak256(bytes(Config.implSalt()));
}

/// @notice Returns the proxy addresses, not reverting if any are unset.
function _proxiesUnstrict() internal view returns (Types.ContractSet memory proxies_) {
proxies_ = Types.ContractSet({
L1CrossDomainMessenger: getAddress("L1CrossDomainMessengerProxy"),
L1StandardBridge: getAddress("L1StandardBridgeProxy"),
L2OutputOracle: getAddress("L2OutputOracleProxy"),
DisputeGameFactory: getAddress("DisputeGameFactoryProxy"),
DelayedWETH: getAddress("DelayedWETHProxy"),
AnchorStateRegistry: getAddress("AnchorStateRegistryProxy"),
OptimismMintableERC20Factory: getAddress("OptimismMintableERC20FactoryProxy"),
OptimismPortal: getAddress("OptimismPortalProxy"),
OptimismPortal2: getAddress("OptimismPortalProxy"),
SystemConfig: getAddress("SystemConfigProxy"),
L1ERC721Bridge: getAddress("L1ERC721BridgeProxy"),
ProtocolVersions: getAddress("ProtocolVersionsProxy"),
SuperchainConfig: getAddress("SuperchainConfigProxy")
});
}

////////////////////////////////////////////////////////////////
// SetUp and Run //
////////////////////////////////////////////////////////////////

/// @notice Deploy all of the L1 contracts necessary for a full Superchain with a single Op Chain.
function run() public {
console.log("Deploying a fresh OP Stack including SuperchainConfig");
_run();
}

/// @notice Internal function containing the deploy logic.
function _run() internal virtual {
console.log("start of L1 Deploy!");
setupSuperchain();
console.log("set up superchain!");
setupOpChain();
console.log("set up op chain!");
deployStorageSetter();
console.log("set up StorageSetter!");
}

////////////////////////////////////////////////////////////////
// High Level Deployment Functions //
////////////////////////////////////////////////////////////////

/// @notice Deploy a full system with a new SuperchainConfig
/// The Superchain system has 2 singleton contracts which lie outside of an OP Chain:
/// 1. The SuperchainConfig contract
/// 2. The ProtocolVersions contract
function setupSuperchain() public {
console.log("Setting up Superchain");
deployERC1967Proxy("SuperchainConfigProxy");
deploySuperchainConfig();
}

/// @notice Deploy a new OP Chain, with an existing SuperchainConfig provided
function setupOpChain() public {
console.log("Deploying OP Chain");

// Ensure that the requisite contracts are deployed
mustGetAddress("SuperchainConfigProxy");
deployImplementations();
}

/// @notice Deploy all of the implementations
function deployImplementations() public {
console.log("Deploying implementations");
deployL1CrossDomainMessenger();
deployOptimismMintableERC20Factory();
deploySystemConfig();
deployL1StandardBridge();
deployL1ERC721Bridge();
deployOptimismPortal();
deployL2OutputOracle();
}

////////////////////////////////////////////////////////////////
// Non-Proxied Deployment Functions //
////////////////////////////////////////////////////////////////


/// @notice Deploy the StorageSetter contract, used for upgrades.
function deployStorageSetter() public broadcast returns (address addr_) {
console.log("Deploying StorageSetter");
StorageSetter setter = new StorageSetter{ salt: _implSalt() }();
console.log("StorageSetter deployed at: %s", address(setter));
string memory version = setter.version();
console.log("StorageSetter version: %s", version);
save("StorageSetter", address(setter));
addr_ = address(setter);
}

////////////////////////////////////////////////////////////////
// Proxy Deployment Functions //
////////////////////////////////////////////////////////////////

/// @notice Deploys an ERC1967Proxy contract with the ProxyAdmin as the owner.
/// @param _name The name of the proxy contract to be deployed.
/// @return addr_ The address of the deployed proxy contract.
function deployERC1967Proxy(string memory _name) public returns (address addr_) {
uint256 chainid = block.chainid;
address proxyAdmin;
if (chainid == Chains.BscTestnet) {
proxyAdmin = Constants.BSCTESTNET_PROXY_ADMIN;
} else if (chainid == Chains.BscMainnet) {
proxyAdmin = Constants.BSCMAINNET_PROXY_ADMIN;
} else if (chainid == Chains.BscQAnet) {
proxyAdmin = Constants.BSCQANET_PROXY_ADMIN;
}
console.log("proxyAdmin is %s", proxyAdmin);
addr_ = deployERC1967ProxyWithOwner(_name, proxyAdmin);
}

/// @notice Deploys an ERC1967Proxy contract with a specified owner.
/// @param _name The name of the proxy contract to be deployed.
/// @param _proxyOwner The address of the owner of the proxy contract.
/// @return addr_ The address of the deployed proxy contract.
function deployERC1967ProxyWithOwner(
string memory _name,
address _proxyOwner
)
public
broadcast
returns (address addr_)
{
console.log(string.concat("Deploying ERC1967 proxy for ", _name));
Proxy proxy = new Proxy({ _admin: _proxyOwner });

require(EIP1967Helper.getAdmin(address(proxy)) == _proxyOwner);

save(_name, address(proxy));
console.log(" at %s", address(proxy));
addr_ = address(proxy);
}

////////////////////////////////////////////////////////////////
// Implementation Deployment Functions //
////////////////////////////////////////////////////////////////

/// @notice Deploy the SuperchainConfig contract
function deploySuperchainConfig() public broadcast {
SuperchainConfig superchainConfig = new SuperchainConfig{ salt: _implSalt() }();

require(superchainConfig.guardian() == address(0));
bytes32 initialized = vm.load(address(superchainConfig), bytes32(0));
require(initialized != 0);

save("SuperchainConfig", address(superchainConfig));
console.log("SuperchainConfig deployed at %s", address(superchainConfig));
}

/// @notice Deploy the L1CrossDomainMessenger
function deployL1CrossDomainMessenger() public broadcast returns (address addr_) {
console.log("Deploying L1CrossDomainMessenger implementation");
L1CrossDomainMessenger messenger = new L1CrossDomainMessenger{ salt: _implSalt() }();

save("L1CrossDomainMessenger", address(messenger));
console.log("L1CrossDomainMessenger deployed at %s", address(messenger));

// Override the `L1CrossDomainMessenger` contract to the deployed implementation. This is necessary
// to check the `L1CrossDomainMessenger` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.L1CrossDomainMessenger = address(messenger);
ChainAssertions.checkL1CrossDomainMessenger({ _contracts: contracts, _vm: vm, _isProxy: false });

addr_ = address(messenger);
}

/// @notice Deploy the OptimismPortal
function deployOptimismPortal() public broadcast returns (address addr_) {
console.log("Deploying OptimismPortal implementation");
addr_ = address(new OptimismPortal{ salt: _implSalt() }());
save("OptimismPortal", addr_);
console.log("OptimismPortal deployed at %s", addr_);

// Override the `OptimismPortal` contract to the deployed implementation. This is necessary
// to check the `OptimismPortal` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.OptimismPortal = addr_;
ChainAssertions.checkOptimismPortal({ _contracts: contracts, _cfg: cfg, _isProxy: false });
}

/// @notice Deploy the L2OutputOracle
function deployL2OutputOracle() public broadcast returns (address addr_) {
console.log("Deploying L2OutputOracle implementation");
L2OutputOracle oracle = new L2OutputOracle{ salt: _implSalt() }();

save("L2OutputOracle", address(oracle));
console.log("L2OutputOracle deployed at %s", address(oracle));

// Override the `L2OutputOracle` contract to the deployed implementation. This is necessary
// to check the `L2OutputOracle` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.L2OutputOracle = address(oracle);
ChainAssertions.checkL2OutputOracle({
_contracts: contracts,
_cfg: cfg,
_l2OutputOracleStartingTimestamp: 0,
_isProxy: false
});

addr_ = address(oracle);
}

/// @notice Deploy the OptimismMintableERC20Factory
function deployOptimismMintableERC20Factory() public broadcast returns (address addr_) {
console.log("Deploying OptimismMintableERC20Factory implementation");
OptimismMintableERC20Factory factory = new OptimismMintableERC20Factory{ salt: _implSalt() }();

save("OptimismMintableERC20Factory", address(factory));
console.log("OptimismMintableERC20Factory deployed at %s", address(factory));

// Override the `OptimismMintableERC20Factory` contract to the deployed implementation. This is necessary
// to check the `OptimismMintableERC20Factory` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.OptimismMintableERC20Factory = address(factory);
ChainAssertions.checkOptimismMintableERC20Factory({ _contracts: contracts, _isProxy: false });

addr_ = address(factory);
}

/// @notice Deploy the ProtocolVersions
function deployProtocolVersions() public broadcast returns (address addr_) {
console.log("Deploying ProtocolVersions implementation");
ProtocolVersions versions = new ProtocolVersions{ salt: _implSalt() }();
save("ProtocolVersions", address(versions));
console.log("ProtocolVersions deployed at %s", address(versions));

// Override the `ProtocolVersions` contract to the deployed implementation. This is necessary
// to check the `ProtocolVersions` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.ProtocolVersions = address(versions);
ChainAssertions.checkProtocolVersions({ _contracts: contracts, _cfg: cfg, _isProxy: false });

addr_ = address(versions);
}

/// @notice Deploy the SystemConfig
function deploySystemConfig() public broadcast returns (address addr_) {
console.log("Deploying SystemConfig implementation");
addr_ = address(new SystemConfig{ salt: _implSalt() }());
save("SystemConfig", addr_);
console.log("SystemConfig deployed at %s", addr_);

// Override the `SystemConfig` contract to the deployed implementation. This is necessary
// to check the `SystemConfig` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.SystemConfig = addr_;
ChainAssertions.checkSystemConfig({ _contracts: contracts, _cfg: cfg, _isProxy: false });
}

/// @notice Deploy the L1StandardBridge
function deployL1StandardBridge() public broadcast returns (address addr_) {
console.log("Deploying L1StandardBridge implementation");

L1StandardBridge bridge = new L1StandardBridge{ salt: _implSalt() }();

save("L1StandardBridge", address(bridge));
console.log("L1StandardBridge deployed at %s", address(bridge));

// Override the `L1StandardBridge` contract to the deployed implementation. This is necessary
// to check the `L1StandardBridge` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.L1StandardBridge = address(bridge);
ChainAssertions.checkL1StandardBridge({ _contracts: contracts, _isProxy: false });

addr_ = address(bridge);
}

/// @notice Deploy the L1ERC721Bridge
function deployL1ERC721Bridge() public broadcast returns (address addr_) {
console.log("Deploying L1ERC721Bridge implementation");
L1ERC721Bridge bridge = new L1ERC721Bridge{ salt: _implSalt() }();

save("L1ERC721Bridge", address(bridge));
console.log("L1ERC721Bridge deployed at %s", address(bridge));

// Override the `L1ERC721Bridge` contract to the deployed implementation. This is necessary
// to check the `L1ERC721Bridge` implementation alongside dependent contracts, which
// are always proxies.
Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.L1ERC721Bridge = address(bridge);

ChainAssertions.checkL1ERC721Bridge({ _contracts: contracts, _isProxy: false });

addr_ = address(bridge);
}
}
8 changes: 8 additions & 0 deletions packages/contracts-bedrock/src/libraries/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ library Constants {
/// transactions.
address internal constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001;

address internal constant BSCTESTNET_PROXY_ADMIN = 0xE4925bD8Ac30b2d4e2bD7b8Ba495a5c92d4c5156;

address internal constant BSCMAINNET_PROXY_ADMIN = 0x27a591Ec09AAfEEb39d7533AEf7C64E0305D1576;

// TODO update for test
address internal constant BSCQANET_PROXY_ADMIN = 0xE4925bD8Ac30b2d4e2bD7b8Ba495a5c92d4c5156;


/// @notice Returns the default values for the ResourceConfig. These are the recommended values
/// for a production network.
function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) {
Expand Down

0 comments on commit a3277e8

Please sign in to comment.