Commit 870f8399 authored by Maurelian's avatar Maurelian

feat(ctb): Perform deployment using gnosis safe as system owner

temp: Add instrumentation to deploy.sol

fix(ctb): Use correct names for deployments

We deploy a SafeProxy contract as the system owner, it needs to be correctly named
in order to connect it to the source code.

The SafeProxyFactory and Safe (as the singleton) are also now saved.

fix(ctb): Skip HH deployments if deployTx not found

At the moment this only applies to the Safe contract, which is deployed in
a nested create2 call. We don't expect we'll need this artifact as it's not a
core part of the OP Stack.
parent 4eece972
......@@ -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";
......@@ -75,6 +79,9 @@ contract Deploy is Deployer {
deployProxies();
deployImplementations();
deploySafe();
transferProxyAdminOwnership(); // to the Safe
initializeDisputeGameFactory();
initializeSystemConfig();
initializeL1StandardBridge();
......@@ -88,7 +95,6 @@ contract Deploy is Deployer {
setAlphabetFaultGameImplementation();
setCannonFaultGameImplementation();
transferProxyAdminOwnership();
transferDisputeGameFactoryOwnership();
}
......@@ -134,7 +140,7 @@ contract Deploy is Deployer {
deployDisputeGameFactoryProxy();
deployProtocolVersionsProxy();
transferAddressManagerOwnership();
transferAddressManagerOwnership(); // to the ProxyAdmin
}
/// @notice Deploy all of the implementations
......@@ -153,6 +159,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();
......@@ -515,16 +555,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();
......@@ -533,17 +604,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(),
......@@ -609,14 +679,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();
......@@ -636,15 +711,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);
......@@ -657,15 +731,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);
......@@ -685,24 +758,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);
......@@ -717,14 +798,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(),
......@@ -755,7 +835,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");
......@@ -766,10 +845,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)
)
......@@ -786,7 +865,6 @@ contract Deploy is Deployer {
}
function initializeProtocolVersions() public onlyTestnetOrDevnet broadcast {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address protocolVersionsProxy = mustGetAddress("ProtocolVersionsProxy");
address protocolVersions = mustGetAddress("ProtocolVersions");
......@@ -794,10 +872,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,
......@@ -820,10 +898,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);
}
}
......@@ -831,10 +909,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