From 256cde9c69a6b7100abc178b6933b85b7573a811 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 17 Jun 2024 11:57:21 -0600 Subject: [PATCH] scripts: Stage 1.4: Deploy FDGF --- rvsol/foundry.toml | 1 + rvsol/scripts/Deploy_Stage_1_4.sol | 205 +++++++++++++++++++++++++++++ rvsol/scripts/deploy_stage_1_4.sh | 25 ++++ 3 files changed, 231 insertions(+) create mode 100644 rvsol/scripts/Deploy_Stage_1_4.sol create mode 100755 rvsol/scripts/deploy_stage_1_4.sh diff --git a/rvsol/foundry.toml b/rvsol/foundry.toml index c295166..c090894 100644 --- a/rvsol/foundry.toml +++ b/rvsol/foundry.toml @@ -11,6 +11,7 @@ remappings = [ '@openzeppelin/contracts/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts/contracts', '@lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/lib', '@solady/=lib/optimism/packages/contracts-bedrock/lib/solady/src', + '@rari-capital/solmate=lib/optimism/packages/contracts-bedrock/lib/solmate', 'safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts', # We need these remappings to use the Optimism monorepo contracts as a library. diff --git a/rvsol/scripts/Deploy_Stage_1_4.sol b/rvsol/scripts/Deploy_Stage_1_4.sol new file mode 100644 index 0000000..b82bc43 --- /dev/null +++ b/rvsol/scripts/Deploy_Stage_1_4.sol @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import { Deployer } from "scripts/Deployer.sol"; +import { IPreimageOracle } from "@optimism/src/cannon/interfaces/IPreimageOracle.sol"; + +import { Config } from "scripts/Config.sol"; + +import { DisputeGameFactory } from "@optimism/src/dispute/DisputeGameFactory.sol"; +import { DelayedWETH } from "@optimism/src/dispute/weth/DelayedWETH.sol"; +import { AnchorStateRegistry } from "@optimism/src/dispute/AnchorStateRegistry.sol"; +import { PreimageOracle } from "@optimism/src/cannon/PreimageOracle.sol"; +import { RISCV } from "../src/RISCV.sol"; +import { Types } from "@optimism/scripts/Types.sol"; +import { OutputRoot, Hash, GameTypes } from "@optimism/src/dispute/lib/Types.sol"; +import { console2 as console } from "forge-std/console2.sol"; + +import { ProxyAdmin } from "@optimism/src/universal/ProxyAdmin.sol"; +import { AddressManager } from "@optimism/src/legacy/AddressManager.sol"; +import { Proxy } from "@optimism/src/universal/Proxy.sol"; +import { EIP1967Helper } from "@optimism/test/mocks/EIP1967Helper.sol"; + +contract Deploy is Deployer { + /// @notice Modifier that wraps a function in broadcasting. + modifier broadcast() { + vm.startBroadcast(msg.sender); + _; + vm.stopBroadcast(); + } + + /// @inheritdoc Deployer + function name() public pure override returns (string memory name_) { + name_ = "Deploy_Stage_1_4"; + } + + function run() public { + // Intentionally not using Safe contracts for brevity + // We do not need AddressManager because no legacies + deployProxyAdmin(); + + deployProxies(); + deployImplementations(); + initializeImplementations(); + } + + /// @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 Deploy RISCV + function deployRiscv() public broadcast returns (address addr_) { + console.log("Deploying RISCV implementation"); + RISCV riscv = new RISCV{ salt: _implSalt() }(IPreimageOracle(mustGetChainAddress("PreimageOracle"))); + save("RISCV", address(riscv)); + console.log("RISCV deployed at %s", address(riscv)); + addr_ = address(riscv); + } + + /// @notice Deploy all of the implementations + function deployImplementations() public { + console.log("Deploying implementations"); + deployDisputeGameFactory(); + deployRiscv(); + deployAnchorStateRegistry(); + } + + /// @notice Deploy all of the proxies + function deployProxies() public { + console.log("Deploying proxies"); + deployERC1967Proxy("DisputeGameFactoryProxy"); + deployERC1967Proxy("AnchorStateRegistryProxy"); + } + + /// @notice Deploy the ProxyAdmin + function deployProxyAdmin() public broadcast returns (address addr_) { + console.log("Deploying ProxyAdmin"); + ProxyAdmin admin = new ProxyAdmin({ _owner: msg.sender }); + require(admin.owner() == msg.sender); + + save("ProxyAdmin", address(admin)); + console.log("ProxyAdmin deployed at %s", address(admin)); + addr_ = address(admin); + } + + /// @notice Deploy the DisputeGameFactory + function deployDisputeGameFactory() public broadcast returns (address addr_) { + console.log("Deploying DisputeGameFactory implementation"); + DisputeGameFactory disputeGameFactory = new DisputeGameFactory{ salt: _implSalt() }(); + save("DisputeGameFactory", address(disputeGameFactory)); + console.log("DisputeGameFactory deployed at %s", address(disputeGameFactory)); + + // Check that the contract is initialized + assertSlotValueIsOne({ _contractAddress: address(disputeGameFactory), _slot: 0, _offset: 0 }); + require(disputeGameFactory.owner() == address(0)); + + addr_ = address(disputeGameFactory); + } + + /// @notice Deploy the AnchorStateRegistry + function deployAnchorStateRegistry() public broadcast returns (address addr_) { + console.log("Deploying AnchorStateRegistry implementation"); + AnchorStateRegistry anchorStateRegistry = + new AnchorStateRegistry{ salt: _implSalt() }(DisputeGameFactory(mustGetAddress("DisputeGameFactory"))); + save("AnchorStateRegistry", address(anchorStateRegistry)); + console.log("AnchorStateRegistry deployed at %s", address(anchorStateRegistry)); + + addr_ = address(anchorStateRegistry); + } + + /// @notice Initialize all of the implementations + function initializeImplementations() public { + console.log("Initializing implementations"); + initializeDisputeGameFactory(); + initializeAnchorStateRegistry(); + } + + /// @notice Initialize the DisputeGameFactory + function initializeDisputeGameFactory() public broadcast { + console.log("Upgrading and initializing DisputeGameFactory"); + address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy"); + address disputeGameFactory = mustGetAddress("DisputeGameFactory"); + + _upgradeAndCall({ + _proxy: payable(disputeGameFactoryProxy), + _implementation: disputeGameFactory, + _innerCallData: abi.encodeCall(DisputeGameFactory.initialize, (msg.sender)) + }); + + string memory version = DisputeGameFactory(disputeGameFactoryProxy).version(); + console.log("DisputeGameFactory version: %s", version); + + // Check that the contract is initialized + assertSlotValueIsOne({ _contractAddress: address(disputeGameFactoryProxy), _slot: 0, _offset: 0 }); + require(DisputeGameFactory(disputeGameFactoryProxy).owner() == msg.sender); + } + + function initializeAnchorStateRegistry() public broadcast { + console.log("Upgrading and initializing AnchorStateRegistry"); + address anchorStateRegistryProxy = mustGetAddress("AnchorStateRegistryProxy"); + address anchorStateRegistry = mustGetAddress("AnchorStateRegistry"); + + AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](1); + roots[0] = AnchorStateRegistry.StartingAnchorRoot({ + gameType: GameTypes.ASTERISC, + outputRoot: OutputRoot({ + root: Hash.wrap(cfg.faultGameGenesisOutputRoot()), + l2BlockNumber: cfg.faultGameGenesisBlock() + }) + }); + + _upgradeAndCall({ + _proxy: payable(anchorStateRegistryProxy), + _implementation: anchorStateRegistry, + _innerCallData: abi.encodeCall(AnchorStateRegistry.initialize, (roots)) + }); + + string memory version = AnchorStateRegistry(payable(anchorStateRegistryProxy)).version(); + console.log("AnchorStateRegistry version: %s", version); + } + + function assertSlotValueIsOne(address _contractAddress, uint256 _slot, uint256 _offset) internal view { + bytes32 slotVal = vm.load(_contractAddress, bytes32(_slot)); + require( + uint8((uint256(slotVal) >> (_offset * 8)) & 0xFF) == uint8(1), + "Storage value is not 1 at the given slot and offset" + ); + } + + function _upgradeAndCall(address _proxy, address _implementation, bytes memory _innerCallData) internal { + ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin")); + proxyAdmin.upgradeAndCall(payable(_proxy), _implementation, _innerCallData); + } + + /// @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_) { + addr_ = deployERC1967ProxyWithOwner(_name, mustGetAddress("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); + } +} diff --git a/rvsol/scripts/deploy_stage_1_4.sh b/rvsol/scripts/deploy_stage_1_4.sh new file mode 100755 index 0000000..7049bb8 --- /dev/null +++ b/rvsol/scripts/deploy_stage_1_4.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -eo pipefail + +TARGET_L1_RPC_URL="${TARGET_L1_RPC_URL:-"http://localhost:8545"}" +# Avoid foundry pre-funded account #4: gnosis safe's owner(0x90F79bf6EB2c4f870365E785982E1f101E93b906) +# to avoid collision +# DEPLOY_PRIVATE_KEY="${DEPLOY_PRIVATE_KEY:-"0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6"}" +DEPLOY_PRIVATE_KEY="${DEPLOY_PRIVATE_KEY:-"0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a"}" + +if [ -z "${TARGET_L2_DEPLOYMENT_FILE}" ]; then + echo "TARGET_L2_DEPLOYMENT_FILE is not set. Must point target chain deployment file (optimism/packages/contracts-bedrock/deployments/devnetL1/.deploy)" + exit 1 +fi + +if [ -z "${TARGET_L2_DEPLOY_CONFIG}" ]; then + echo "TARGET_L2_DEPLOY_CONFIG is not set. Must point target chain deploy config file (optimism/packages/contracts-bedrock/deploy-config/devnetL1.json)" + exit 1 +fi +SCRIPTS_DIR="$(dirname "$(realpath "$0")")" +LOCAL_DEPLOY_CONFIG_PATH="$(dirname "${SCRIPTS_DIR}")/deploy-config.json" +cp "$TARGET_L2_DEPLOY_CONFIG" "$LOCAL_DEPLOY_CONFIG_PATH" + + +echo "> Deploying contracts" +TARGET_L2_DEPLOY_CONFIG=$LOCAL_DEPLOY_CONFIG_PATH forge script -vvv "${SCRIPTS_DIR}"/Deploy_Stage_1_4.sol:Deploy --rpc-url "$TARGET_L1_RPC_URL" --broadcast --private-key "$DEPLOY_PRIVATE_KEY"