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"; ...@@ -6,6 +6,10 @@ import { Script } from "forge-std/Script.sol";
import { console2 as console } from "forge-std/console2.sol"; import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.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 { Deployer } from "./Deployer.sol";
import { DeployConfig } from "./DeployConfig.s.sol"; import { DeployConfig } from "./DeployConfig.s.sol";
...@@ -70,6 +74,9 @@ contract Deploy is Deployer { ...@@ -70,6 +74,9 @@ contract Deploy is Deployer {
deployProxies(); deployProxies();
deployImplementations(); deployImplementations();
deploySafe();
transferProxyAdminOwnership(); // to the Safe
initializeDisputeGameFactory(); initializeDisputeGameFactory();
initializeSystemConfig(); initializeSystemConfig();
initializeL1StandardBridge(); initializeL1StandardBridge();
...@@ -83,7 +90,6 @@ contract Deploy is Deployer { ...@@ -83,7 +90,6 @@ contract Deploy is Deployer {
setAlphabetFaultGameImplementation(); setAlphabetFaultGameImplementation();
setCannonFaultGameImplementation(); setCannonFaultGameImplementation();
transferProxyAdminOwnership();
transferDisputeGameFactoryOwnership(); transferDisputeGameFactoryOwnership();
} }
...@@ -136,7 +142,7 @@ contract Deploy is Deployer { ...@@ -136,7 +142,7 @@ contract Deploy is Deployer {
deployDisputeGameFactoryProxy(); deployDisputeGameFactoryProxy();
deployProtocolVersionsProxy(); deployProtocolVersionsProxy();
transferAddressManagerOwnership(); transferAddressManagerOwnership(); // to the ProxyAdmin
} }
/// @notice Deploy all of the implementations /// @notice Deploy all of the implementations
...@@ -155,6 +161,40 @@ contract Deploy is Deployer { ...@@ -155,6 +161,40 @@ contract Deploy is Deployer {
deployProtocolVersions(); 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 /// @notice Deploy the AddressManager
function deployAddressManager() public broadcast returns (address addr_) { function deployAddressManager() public broadcast returns (address addr_) {
AddressManager manager = new AddressManager(); AddressManager manager = new AddressManager();
...@@ -517,16 +557,47 @@ contract Deploy is Deployer { ...@@ -517,16 +557,47 @@ contract Deploy is Deployer {
require(addressManager.owner() == proxyAdmin); 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 /// @notice Initialize the DisputeGameFactory
function initializeDisputeGameFactory() public onlyDevnet broadcast { function initializeDisputeGameFactory() public onlyDevnet broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy"); address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy");
address disputeGameFactory = mustGetAddress("DisputeGameFactory"); address disputeGameFactory = mustGetAddress("DisputeGameFactory");
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(disputeGameFactoryProxy), _proxy: payable(disputeGameFactoryProxy),
_implementation: disputeGameFactory, _implementation: disputeGameFactory,
_data: abi.encodeCall(DisputeGameFactory.initialize, (msg.sender)) _innerCallData: abi.encodeCall(DisputeGameFactory.initialize, (msg.sender))
}); });
string memory version = DisputeGameFactory(disputeGameFactoryProxy).version(); string memory version = DisputeGameFactory(disputeGameFactoryProxy).version();
...@@ -535,17 +606,16 @@ contract Deploy is Deployer { ...@@ -535,17 +606,16 @@ contract Deploy is Deployer {
/// @notice Initialize the SystemConfig /// @notice Initialize the SystemConfig
function initializeSystemConfig() public broadcast { function initializeSystemConfig() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address systemConfigProxy = mustGetAddress("SystemConfigProxy"); address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address systemConfig = mustGetAddress("SystemConfig"); address systemConfig = mustGetAddress("SystemConfig");
bytes32 batcherHash = bytes32(uint256(uint160(cfg.batchSenderAddress()))); bytes32 batcherHash = bytes32(uint256(uint160(cfg.batchSenderAddress())));
uint256 startBlock = cfg.systemConfigStartBlock(); uint256 startBlock = cfg.systemConfigStartBlock();
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(systemConfigProxy), _proxy: payable(systemConfigProxy),
_implementation: systemConfig, _implementation: systemConfig,
_data: abi.encodeCall( _innerCallData: abi.encodeCall(
SystemConfig.initialize, SystemConfig.initialize,
( (
cfg.finalSystemOwner(), cfg.finalSystemOwner(),
...@@ -611,14 +681,19 @@ contract Deploy is Deployer { ...@@ -611,14 +681,19 @@ contract Deploy is Deployer {
uint256 proxyType = uint256(proxyAdmin.proxyType(l1StandardBridgeProxy)); uint256 proxyType = uint256(proxyAdmin.proxyType(l1StandardBridgeProxy));
if (proxyType != uint256(ProxyAdmin.ProxyType.CHUGSPLASH)) { 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)); require(uint256(proxyAdmin.proxyType(l1StandardBridgeProxy)) == uint256(ProxyAdmin.ProxyType.CHUGSPLASH));
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(l1StandardBridgeProxy), _proxy: payable(l1StandardBridgeProxy),
_implementation: l1StandardBridge, _implementation: l1StandardBridge,
_data: abi.encodeCall(L1StandardBridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy))) _innerCallData: abi.encodeCall(
L1StandardBridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy))
)
}); });
string memory version = L1StandardBridge(payable(l1StandardBridgeProxy)).version(); string memory version = L1StandardBridge(payable(l1StandardBridgeProxy)).version();
...@@ -638,15 +713,14 @@ contract Deploy is Deployer { ...@@ -638,15 +713,14 @@ contract Deploy is Deployer {
/// @notice Initialize the L1ERC721Bridge /// @notice Initialize the L1ERC721Bridge
function initializeL1ERC721Bridge() public broadcast { function initializeL1ERC721Bridge() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address l1ERC721BridgeProxy = mustGetAddress("L1ERC721BridgeProxy"); address l1ERC721BridgeProxy = mustGetAddress("L1ERC721BridgeProxy");
address l1ERC721Bridge = mustGetAddress("L1ERC721Bridge"); address l1ERC721Bridge = mustGetAddress("L1ERC721Bridge");
address l1CrossDomainMessengerProxy = mustGetAddress("L1CrossDomainMessengerProxy"); address l1CrossDomainMessengerProxy = mustGetAddress("L1CrossDomainMessengerProxy");
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(l1ERC721BridgeProxy), _proxy: payable(l1ERC721BridgeProxy),
_implementation: l1ERC721Bridge, _implementation: l1ERC721Bridge,
_data: abi.encodeCall(L1ERC721Bridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy))) _innerCallData: abi.encodeCall(L1ERC721Bridge.initialize, (L1CrossDomainMessenger(l1CrossDomainMessengerProxy)))
}); });
L1ERC721Bridge bridge = L1ERC721Bridge(l1ERC721BridgeProxy); L1ERC721Bridge bridge = L1ERC721Bridge(l1ERC721BridgeProxy);
...@@ -659,15 +733,14 @@ contract Deploy is Deployer { ...@@ -659,15 +733,14 @@ contract Deploy is Deployer {
/// @notice Ininitialize the OptimismMintableERC20Factory /// @notice Ininitialize the OptimismMintableERC20Factory
function initializeOptimismMintableERC20Factory() public broadcast { function initializeOptimismMintableERC20Factory() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address optimismMintableERC20FactoryProxy = mustGetAddress("OptimismMintableERC20FactoryProxy"); address optimismMintableERC20FactoryProxy = mustGetAddress("OptimismMintableERC20FactoryProxy");
address optimismMintableERC20Factory = mustGetAddress("OptimismMintableERC20Factory"); address optimismMintableERC20Factory = mustGetAddress("OptimismMintableERC20Factory");
address l1StandardBridgeProxy = mustGetAddress("L1StandardBridgeProxy"); address l1StandardBridgeProxy = mustGetAddress("L1StandardBridgeProxy");
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(optimismMintableERC20FactoryProxy), _proxy: payable(optimismMintableERC20FactoryProxy),
_implementation: optimismMintableERC20Factory, _implementation: optimismMintableERC20Factory,
_data: abi.encodeCall(OptimismMintableERC20Factory.initialize, (l1StandardBridgeProxy)) _innerCallData: abi.encodeCall(OptimismMintableERC20Factory.initialize, (l1StandardBridgeProxy))
}); });
OptimismMintableERC20Factory factory = OptimismMintableERC20Factory(optimismMintableERC20FactoryProxy); OptimismMintableERC20Factory factory = OptimismMintableERC20Factory(optimismMintableERC20FactoryProxy);
...@@ -687,24 +760,32 @@ contract Deploy is Deployer { ...@@ -687,24 +760,32 @@ contract Deploy is Deployer {
uint256 proxyType = uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy)); uint256 proxyType = uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy));
if (proxyType != uint256(ProxyAdmin.ProxyType.RESOLVED)) { 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)); require(uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy)) == uint256(ProxyAdmin.ProxyType.RESOLVED));
string memory contractName = "OVM_L1CrossDomainMessenger"; string memory contractName = "OVM_L1CrossDomainMessenger";
string memory implName = proxyAdmin.implementationName(l1CrossDomainMessenger); string memory implName = proxyAdmin.implementationName(l1CrossDomainMessenger);
if (keccak256(bytes(contractName)) != keccak256(bytes(implName))) { if (keccak256(bytes(contractName)) != keccak256(bytes(implName))) {
proxyAdmin.setImplementationName(l1CrossDomainMessengerProxy, contractName); _callViaSafe({
_target: address(proxyAdmin),
_data: abi.encodeCall(ProxyAdmin.setImplementationName, (l1CrossDomainMessengerProxy, contractName))
});
} }
require( require(
keccak256(bytes(proxyAdmin.implementationName(l1CrossDomainMessengerProxy))) keccak256(bytes(proxyAdmin.implementationName(l1CrossDomainMessengerProxy)))
== keccak256(bytes(contractName)) == keccak256(bytes(contractName))
); );
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(l1CrossDomainMessengerProxy), _proxy: payable(l1CrossDomainMessengerProxy),
_implementation: l1CrossDomainMessenger, _implementation: l1CrossDomainMessenger,
_data: abi.encodeCall(L1CrossDomainMessenger.initialize, (OptimismPortal(payable(optimismPortalProxy)))) _innerCallData: abi.encodeCall(
L1CrossDomainMessenger.initialize, (OptimismPortal(payable(optimismPortalProxy)))
)
}); });
L1CrossDomainMessenger messenger = L1CrossDomainMessenger(l1CrossDomainMessengerProxy); L1CrossDomainMessenger messenger = L1CrossDomainMessenger(l1CrossDomainMessengerProxy);
...@@ -719,14 +800,13 @@ contract Deploy is Deployer { ...@@ -719,14 +800,13 @@ contract Deploy is Deployer {
/// @notice Initialize the L2OutputOracle /// @notice Initialize the L2OutputOracle
function initializeL2OutputOracle() public broadcast { function initializeL2OutputOracle() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy"); address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
address l2OutputOracle = mustGetAddress("L2OutputOracle"); address l2OutputOracle = mustGetAddress("L2OutputOracle");
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(l2OutputOracleProxy), _proxy: payable(l2OutputOracleProxy),
_implementation: l2OutputOracle, _implementation: l2OutputOracle,
_data: abi.encodeCall( _innerCallData: abi.encodeCall(
L2OutputOracle.initialize, L2OutputOracle.initialize,
( (
cfg.l2OutputOracleStartingBlockNumber(), cfg.l2OutputOracleStartingBlockNumber(),
...@@ -757,7 +837,6 @@ contract Deploy is Deployer { ...@@ -757,7 +837,6 @@ contract Deploy is Deployer {
/// @notice Initialize the OptimismPortal /// @notice Initialize the OptimismPortal
function initializeOptimismPortal() public broadcast { function initializeOptimismPortal() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address optimismPortalProxy = mustGetAddress("OptimismPortalProxy"); address optimismPortalProxy = mustGetAddress("OptimismPortalProxy");
address optimismPortal = mustGetAddress("OptimismPortal"); address optimismPortal = mustGetAddress("OptimismPortal");
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy"); address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
...@@ -768,10 +847,10 @@ contract Deploy is Deployer { ...@@ -768,10 +847,10 @@ contract Deploy is Deployer {
console.log("Portal guardian has no code: %s", guardian); console.log("Portal guardian has no code: %s", guardian);
} }
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(optimismPortalProxy), _proxy: payable(optimismPortalProxy),
_implementation: optimismPortal, _implementation: optimismPortal,
_data: abi.encodeCall( _innerCallData: abi.encodeCall(
OptimismPortal.initialize, OptimismPortal.initialize,
(L2OutputOracle(l2OutputOracleProxy), guardian, SystemConfig(systemConfigProxy), false) (L2OutputOracle(l2OutputOracleProxy), guardian, SystemConfig(systemConfigProxy), false)
) )
...@@ -788,7 +867,6 @@ contract Deploy is Deployer { ...@@ -788,7 +867,6 @@ contract Deploy is Deployer {
} }
function initializeProtocolVersions() public onlyTestnetOrDevnet broadcast { function initializeProtocolVersions() public onlyTestnetOrDevnet broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address protocolVersionsProxy = mustGetAddress("ProtocolVersionsProxy"); address protocolVersionsProxy = mustGetAddress("ProtocolVersionsProxy");
address protocolVersions = mustGetAddress("ProtocolVersions"); address protocolVersions = mustGetAddress("ProtocolVersions");
...@@ -796,10 +874,10 @@ contract Deploy is Deployer { ...@@ -796,10 +874,10 @@ contract Deploy is Deployer {
uint256 requiredProtocolVersion = cfg.requiredProtocolVersion(); uint256 requiredProtocolVersion = cfg.requiredProtocolVersion();
uint256 recommendedProtocolVersion = cfg.recommendedProtocolVersion(); uint256 recommendedProtocolVersion = cfg.recommendedProtocolVersion();
proxyAdmin.upgradeAndCall({ _upgradeAndCallViaSafe({
_proxy: payable(protocolVersionsProxy), _proxy: payable(protocolVersionsProxy),
_implementation: protocolVersions, _implementation: protocolVersions,
_data: abi.encodeCall( _innerCallData: abi.encodeCall(
ProtocolVersions.initialize, ProtocolVersions.initialize,
( (
finalSystemOwner, finalSystemOwner,
...@@ -822,10 +900,10 @@ contract Deploy is Deployer { ...@@ -822,10 +900,10 @@ contract Deploy is Deployer {
function transferProxyAdminOwnership() public broadcast { function transferProxyAdminOwnership() public broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin")); ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address owner = proxyAdmin.owner(); address owner = proxyAdmin.owner();
address finalSystemOwner = cfg.finalSystemOwner(); address safe = mustGetAddress("SystemOwnerSafe");
if (owner != finalSystemOwner) { if (owner != safe) {
proxyAdmin.transferOwnership(finalSystemOwner); proxyAdmin.transferOwnership(safe);
console.log("ProxyAdmin ownership transferred to: %s", finalSystemOwner); console.log("ProxyAdmin ownership transferred to Safe at: %s", safe);
} }
} }
...@@ -833,10 +911,11 @@ contract Deploy is Deployer { ...@@ -833,10 +911,11 @@ contract Deploy is Deployer {
function transferDisputeGameFactoryOwnership() public onlyDevnet broadcast { function transferDisputeGameFactoryOwnership() public onlyDevnet broadcast {
DisputeGameFactory disputeGameFactory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy")); DisputeGameFactory disputeGameFactory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
address owner = disputeGameFactory.owner(); address owner = disputeGameFactory.owner();
address finalSystemOwner = cfg.finalSystemOwner();
if (owner != finalSystemOwner) { address safe = mustGetAddress("SystemOwnerSafe");
disputeGameFactory.transferOwnership(finalSystemOwner); if (owner != safe) {
console.log("DisputeGameFactory ownership transferred to: %s", finalSystemOwner); disputeGameFactory.transferOwnership(safe);
console.log("DisputeGameFactory ownership transferred to Safe at: %s", safe);
} }
} }
......
...@@ -115,6 +115,10 @@ abstract contract Deployer is Script { ...@@ -115,6 +115,10 @@ abstract contract Deployer is Script {
string memory deploymentName = deployments[i].name; string memory deploymentName = deployments[i].name;
string memory deployTx = _getDeployTransactionByContractAddress(addr); 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); string memory contractName = _getContractNameFromDeployTransaction(deployTx);
console.log("Syncing deployment %s: contract %s", deploymentName, contractName); 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