-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#!/usr/bin/env bash | ||
set -eo pipefail | ||
|
||
TARGET_L1_RPC_URL="${TARGET_L1_RPC_URL:-"http://localhost:8545"}" | ||
# foundry pre-funded account #4: gnosis safe's owner(0x90F79bf6EB2c4f870365E785982E1f101E93b906) | ||
# 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" |