Commit adb95958 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #7292 from ethereum-optimism/jm/deploy-via-safe

Deploy via Safe
parents 911394b0 18478305
......@@ -6,6 +6,10 @@ import { Script } from "forge-std/Script.sol";
import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.sol";
import { Safe } from "safe-contracts/Safe.sol";
import { SafeProxyFactory } from "safe-contracts/proxies/SafeProxyFactory.sol";
import { Enum as SafeOps } from "safe-contracts/common/Enum.sol";
import { Deployer } from "./Deployer.sol";
import { DeployConfig } from "./DeployConfig.s.sol";
......@@ -70,6 +74,9 @@ contract Deploy is Deployer {
deployProxies();
deployImplementations();
deploySafe();
transferProxyAdminOwnership(); // to the Safe
initializeDisputeGameFactory();
initializeSystemConfig();
initializeL1StandardBridge();
......@@ -83,7 +90,6 @@ contract Deploy is Deployer {
setAlphabetFaultGameImplementation();
setCannonFaultGameImplementation();
transferProxyAdminOwnership();
transferDisputeGameFactoryOwnership();
}
......@@ -136,7 +142,7 @@ contract Deploy is Deployer {
deployDisputeGameFactoryProxy();
deployProtocolVersionsProxy();
transferAddressManagerOwnership();
transferAddressManagerOwnership(); // to the ProxyAdmin
}
/// @notice Deploy all of the implementations
......@@ -155,6 +161,40 @@ contract Deploy is Deployer {
deployProtocolVersions();
}
// @notice Gets the address of the SafeProxyFactory and Safe singleton for use in deploying a new GnosisSafe.
function _getSafeFactory() internal returns (SafeProxyFactory safeProxyFactory_, Safe safeSingleton_) {
// These are they standard create2 deployed contracts. First we'll check if they are deployed,
// if not we'll deploy new ones, though not at these addresses.
address safeProxyFactory = 0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2;
address safeSingleton = 0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552;
safeProxyFactory.code.length == 0
? safeProxyFactory_ = new SafeProxyFactory()
: safeProxyFactory_ = SafeProxyFactory(safeProxyFactory);
safeSingleton.code.length == 0 ? safeSingleton_ = new Safe() : safeSingleton_ = Safe(payable(safeSingleton_));
save("SafeProxyFactory", address(safeProxyFactory_));
save("SafeSingleton", address(safeSingleton_));
}
/// @notice Deploy the Safe
function deploySafe() public broadcast returns (address addr_) {
(SafeProxyFactory safeProxyFactory, Safe safeSingleton) = _getSafeFactory();
address[] memory signers = new address[](1);
signers[0] = msg.sender;
bytes memory initData = abi.encodeWithSelector(
Safe.setup.selector, signers, 1, address(0), hex"", address(0), address(0), 0, address(0)
);
address safe = address(safeProxyFactory.createProxyWithNonce(address(safeSingleton), initData, block.timestamp));
save("SystemOwnerSafe", address(safe));
console.log("New SystemOwnerSafe deployed at %s", address(safe));
addr_ = safe;
}
/// @notice Deploy the AddressManager
function deployAddressManager() public broadcast returns (address addr_) {
AddressManager manager = new AddressManager();
......@@ -517,16 +557,47 @@ contract Deploy is Deployer {
require(addressManager.owner() == proxyAdmin);
}
/// @notice Make a call from the Safe contract to an arbitrary address with arbitrary data
function _callViaSafe(address _target, bytes memory _data) internal {
Safe safe = Safe(mustGetAddress("SystemOwnerSafe"));
// This is the signature format used the caller is also the signer.
bytes memory signature = abi.encodePacked(uint256(uint160(msg.sender)), bytes32(0), uint8(1));
safe.execTransaction({
to: _target,
value: 0,
data: _data,
operation: SafeOps.Operation.Call,
safeTxGas: 0,
baseGas: 0,
gasPrice: 0,
gasToken: address(0),
refundReceiver: payable(address(0)),
signatures: signature
});
}
/// @notice Call from the Safe contract to the Proxy Admin's upgrade and call method
function _upgradeAndCallViaSafe(address _proxy, address _implementation, bytes memory _innerCallData) internal {
Safe safe = Safe(mustGetAddress("SystemOwnerSafe"));
address proxyAdmin = mustGetAddress("ProxyAdmin");
bytes memory data =
abi.encodeCall(ProxyAdmin.upgradeAndCall, (payable(_proxy), _implementation, _innerCallData));
_callViaSafe({ _target: proxyAdmin, _data: data });
}
/// @notice Initialize the DisputeGameFactory
function initializeDisputeGameFactory() public onlyDevnet broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy");
address disputeGameFactory = mustGetAddress("DisputeGameFactory");
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(disputeGameFactoryProxy),
_implementation: disputeGameFactory,
_data: abi.encodeCall(DisputeGameFactory.initialize, (msg.sender))
_innerCallData: abi.encodeCall(DisputeGameFactory.initialize, (msg.sender))
});
string memory version = DisputeGameFactory(disputeGameFactoryProxy).version();
......@@ -535,17 +606,16 @@ contract Deploy is Deployer {
/// @notice Initialize the SystemConfig
function initializeSystemConfig() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address systemConfig = mustGetAddress("SystemConfig");
bytes32 batcherHash = bytes32(uint256(uint160(cfg.batchSenderAddress())));
uint256 startBlock = cfg.systemConfigStartBlock();
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(systemConfigProxy),
_implementation: systemConfig,
_data: abi.encodeCall(
_innerCallData: abi.encodeCall(
SystemConfig.initialize,
(
cfg.finalSystemOwner(),
......@@ -611,14 +681,19 @@ contract Deploy is Deployer {
uint256 proxyType = uint256(proxyAdmin.proxyType(l1StandardBridgeProxy));
if (proxyType != uint256(ProxyAdmin.ProxyType.CHUGSPLASH)) {
proxyAdmin.setProxyType(l1StandardBridgeProxy, ProxyAdmin.ProxyType.CHUGSPLASH);
_callViaSafe({
_target: address(proxyAdmin),
_data: abi.encodeCall(ProxyAdmin.setProxyType, (l1StandardBridgeProxy, ProxyAdmin.ProxyType.CHUGSPLASH))
});
}
require(uint256(proxyAdmin.proxyType(l1StandardBridgeProxy)) == uint256(ProxyAdmin.ProxyType.CHUGSPLASH));
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(l1StandardBridgeProxy),
_implementation: l1StandardBridge,
_data: abi.encodeCall(L1StandardBridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy)))
_innerCallData: abi.encodeCall(
L1StandardBridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy))
)
});
string memory version = L1StandardBridge(payable(l1StandardBridgeProxy)).version();
......@@ -638,15 +713,14 @@ contract Deploy is Deployer {
/// @notice Initialize the L1ERC721Bridge
function initializeL1ERC721Bridge() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address l1ERC721BridgeProxy = mustGetAddress("L1ERC721BridgeProxy");
address l1ERC721Bridge = mustGetAddress("L1ERC721Bridge");
address l1CrossDomainMessengerProxy = mustGetAddress("L1CrossDomainMessengerProxy");
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(l1ERC721BridgeProxy),
_implementation: l1ERC721Bridge,
_data: abi.encodeCall(L1ERC721Bridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy)))
_innerCallData: abi.encodeCall(L1ERC721Bridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy)))
});
L1ERC721Bridge bridge = L1ERC721Bridge(l1ERC721BridgeProxy);
......@@ -659,15 +733,14 @@ contract Deploy is Deployer {
/// @notice Ininitialize the OptimismMintableERC20Factory
function initializeOptimismMintableERC20Factory() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address optimismMintableERC20FactoryProxy = mustGetAddress("OptimismMintableERC20FactoryProxy");
address optimismMintableERC20Factory = mustGetAddress("OptimismMintableERC20Factory");
address l1StandardBridgeProxy = mustGetAddress("L1StandardBridgeProxy");
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(optimismMintableERC20FactoryProxy),
_implementation: optimismMintableERC20Factory,
_data: abi.encodeCall(OptimismMintableERC20Factory.initialize, (l1StandardBridgeProxy))
_innerCallData: abi.encodeCall(OptimismMintableERC20Factory.initialize, (l1StandardBridgeProxy))
});
OptimismMintableERC20Factory factory = OptimismMintableERC20Factory(optimismMintableERC20FactoryProxy);
......@@ -687,24 +760,32 @@ contract Deploy is Deployer {
uint256 proxyType = uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy));
if (proxyType != uint256(ProxyAdmin.ProxyType.RESOLVED)) {
proxyAdmin.setProxyType(l1CrossDomainMessengerProxy, ProxyAdmin.ProxyType.RESOLVED);
_callViaSafe({
_target: address(proxyAdmin),
_data: abi.encodeCall(ProxyAdmin.setProxyType, (l1CrossDomainMessengerProxy, ProxyAdmin.ProxyType.RESOLVED))
});
}
require(uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy)) == uint256(ProxyAdmin.ProxyType.RESOLVED));
string memory contractName = "OVM_L1CrossDomainMessenger";
string memory implName = proxyAdmin.implementationName(l1CrossDomainMessenger);
if (keccak256(bytes(contractName)) != keccak256(bytes(implName))) {
proxyAdmin.setImplementationName(l1CrossDomainMessengerProxy, contractName);
_callViaSafe({
_target: address(proxyAdmin),
_data: abi.encodeCall(ProxyAdmin.setImplementationName, (l1CrossDomainMessengerProxy, contractName))
});
}
require(
keccak256(bytes(proxyAdmin.implementationName(l1CrossDomainMessengerProxy)))
== keccak256(bytes(contractName))
);
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(l1CrossDomainMessengerProxy),
_implementation: l1CrossDomainMessenger,
_data: abi.encodeCall(L1CrossDomainMessenger.initialize, (OptimismPortal(payable(optimismPortalProxy))))
_innerCallData: abi.encodeCall(
L1CrossDomainMessenger.initialize, (OptimismPortal(payable(optimismPortalProxy)))
)
});
L1CrossDomainMessenger messenger = L1CrossDomainMessenger(l1CrossDomainMessengerProxy);
......@@ -719,14 +800,13 @@ contract Deploy is Deployer {
/// @notice Initialize the L2OutputOracle
function initializeL2OutputOracle() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
address l2OutputOracle = mustGetAddress("L2OutputOracle");
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(l2OutputOracleProxy),
_implementation: l2OutputOracle,
_data: abi.encodeCall(
_innerCallData: abi.encodeCall(
L2OutputOracle.initialize,
(
cfg.l2OutputOracleStartingBlockNumber(),
......@@ -757,7 +837,6 @@ contract Deploy is Deployer {
/// @notice Initialize the OptimismPortal
function initializeOptimismPortal() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address optimismPortalProxy = mustGetAddress("OptimismPortalProxy");
address optimismPortal = mustGetAddress("OptimismPortal");
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
......@@ -768,10 +847,10 @@ contract Deploy is Deployer {
console.log("Portal guardian has no code: %s", guardian);
}
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(optimismPortalProxy),
_implementation: optimismPortal,
_data: abi.encodeCall(
_innerCallData: abi.encodeCall(
OptimismPortal.initialize,
(L2OutputOracle(l2OutputOracleProxy), guardian, SystemConfig(systemConfigProxy), false)
)
......@@ -788,7 +867,6 @@ contract Deploy is Deployer {
}
function initializeProtocolVersions() public onlyTestnetOrDevnet broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address protocolVersionsProxy = mustGetAddress("ProtocolVersionsProxy");
address protocolVersions = mustGetAddress("ProtocolVersions");
......@@ -796,10 +874,10 @@ contract Deploy is Deployer {
uint256 requiredProtocolVersion = cfg.requiredProtocolVersion();
uint256 recommendedProtocolVersion = cfg.recommendedProtocolVersion();
proxyAdmin.upgradeAndCall({
_upgradeAndCallViaSafe({
_proxy: payable(protocolVersionsProxy),
_implementation: protocolVersions,
_data: abi.encodeCall(
_innerCallData: abi.encodeCall(
ProtocolVersions.initialize,
(
finalSystemOwner,
......@@ -822,10 +900,10 @@ contract Deploy is Deployer {
function transferProxyAdminOwnership() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address owner = proxyAdmin.owner();
address finalSystemOwner = cfg.finalSystemOwner();
if (owner != finalSystemOwner) {
proxyAdmin.transferOwnership(finalSystemOwner);
console.log("ProxyAdmin ownership transferred to: %s", finalSystemOwner);
address safe = mustGetAddress("SystemOwnerSafe");
if (owner != safe) {
proxyAdmin.transferOwnership(safe);
console.log("ProxyAdmin ownership transferred to Safe at: %s", safe);
}
}
......@@ -833,10 +911,11 @@ contract Deploy is Deployer {
function transferDisputeGameFactoryOwnership() public onlyDevnet broadcast {
DisputeGameFactory disputeGameFactory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
address owner = disputeGameFactory.owner();
address finalSystemOwner = cfg.finalSystemOwner();
if (owner != finalSystemOwner) {
disputeGameFactory.transferOwnership(finalSystemOwner);
console.log("DisputeGameFactory ownership transferred to: %s", finalSystemOwner);
address safe = mustGetAddress("SystemOwnerSafe");
if (owner != safe) {
disputeGameFactory.transferOwnership(safe);
console.log("DisputeGameFactory ownership transferred to Safe at: %s", safe);
}
}
......
......@@ -115,6 +115,10 @@ abstract contract Deployer is Script {
string memory deploymentName = deployments[i].name;
string memory deployTx = _getDeployTransactionByContractAddress(addr);
if (bytes(deployTx).length == 0) {
console.log("Deploy Tx not found for %s skipping deployment artifact generation", deploymentName);
continue;
}
string memory contractName = _getContractNameFromDeployTransaction(deployTx);
console.log("Syncing deployment %s: contract %s", deploymentName, contractName);
......
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