Commit cd1cc103 authored by Maurelian's avatar Maurelian Committed by GitHub

test: Transfer to finalSystemOwner rather than SystemOwnerSafe (#12116)

* test: Transfer to finalSystemOwner rather than SystemOwnerSafe

* feat: Fix comment references to ProxyAdmin
parent d3402628
...@@ -2,7 +2,6 @@ package gastoken ...@@ -2,7 +2,6 @@ package gastoken
import ( import (
"context" "context"
"fmt"
"math/big" "math/big"
"testing" "testing"
"time" "time"
...@@ -440,34 +439,6 @@ func TestCustomGasToken(t *testing.T) { ...@@ -440,34 +439,6 @@ func TestCustomGasToken(t *testing.T) {
checkFeeWithdrawal(t, enabled) checkFeeWithdrawal(t, enabled)
} }
// callViaSafe will use the Safe smart account at safeAddress to send a transaction to target using the provided data. The transaction signature is constructed from
// the supplied opts.
func callViaSafe(opts *bind.TransactOpts, client *ethclient.Client, safeAddress common.Address, target common.Address, data []byte) (*types.Transaction, error) {
signature := [65]byte{}
copy(signature[12:], opts.From[:])
signature[64] = uint8(1)
safe, err := bindings.NewSafe(safeAddress, client)
if err != nil {
return nil, err
}
owners, err := safe.GetOwners(&bind.CallOpts{})
if err != nil {
return nil, err
}
isOwner, err := safe.IsOwner(&bind.CallOpts{}, opts.From)
if err != nil {
return nil, err
}
if !isOwner {
return nil, fmt.Errorf("address %s is not in owners list %s", opts.From, owners)
}
return safe.ExecTransaction(opts, target, big.NewInt(0), data, 0, big.NewInt(0), big.NewInt(0), big.NewInt(0), common.Address{}, common.Address{}, signature[:])
}
// setCustomGasToeken enables the Custom Gas Token feature on a chain where it wasn't enabled at genesis. // setCustomGasToeken enables the Custom Gas Token feature on a chain where it wasn't enabled at genesis.
// It reads existing parameters from the SystemConfig contract, inserts the supplied cgtAddress and reinitializes that contract. // It reads existing parameters from the SystemConfig contract, inserts the supplied cgtAddress and reinitializes that contract.
// To do this it uses the ProxyAdmin and StorageSetter from the supplied cfg. // To do this it uses the ProxyAdmin and StorageSetter from the supplied cfg.
...@@ -518,27 +489,18 @@ func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System ...@@ -518,27 +489,18 @@ func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System
proxyAdmin, err := bindings.NewProxyAdmin(cfg.L1Deployments.ProxyAdmin, l1Client) proxyAdmin, err := bindings.NewProxyAdmin(cfg.L1Deployments.ProxyAdmin, l1Client)
require.NoError(t, err) require.NoError(t, err)
// Compute Proxy Admin Owner (this is a SAFE with 1 owner)
proxyAdminOwner, err := proxyAdmin.Owner(&bind.CallOpts{})
require.NoError(t, err)
// Deploy a new StorageSetter contract // Deploy a new StorageSetter contract
storageSetterAddr, tx, _, err := bindings.DeployStorageSetter(deployerOpts, l1Client) storageSetterAddr, tx, _, err := bindings.DeployStorageSetter(deployerOpts, l1Client)
waitForTx(t, tx, err, l1Client) waitForTx(t, tx, err, l1Client)
// Set up a signer which controls the Proxy Admin Owner SAFE // Set up a signer which controls the Proxy Admin.
safeOwnerOpts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Deployer, cfg.L1ChainIDBig()) // The deploy config's finalSystemOwner is the owner of the ProxyAdmin as well as the SystemConfig,
require.NoError(t, err) // so we can use that address for the proxy admin owner.
proxyAdminOwnerOpts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.SysCfgOwner, cfg.L1ChainIDBig())
// Encode calldata for upgrading SystemConfigProxy to the StorageSetter implementation
proxyAdminABI, err := bindings.ProxyAdminMetaData.GetAbi()
require.NoError(t, err)
encodedUpgradeCall, err := proxyAdminABI.Pack("upgrade",
cfg.L1Deployments.SystemConfigProxy, storageSetterAddr)
require.NoError(t, err) require.NoError(t, err)
// Execute the upgrade SystemConfigProxy -> StorageSetter // Execute the upgrade SystemConfigProxy -> StorageSetter via ProxyAdmin
tx, err = callViaSafe(safeOwnerOpts, l1Client, proxyAdminOwner, cfg.L1Deployments.ProxyAdmin, encodedUpgradeCall) tx, err = proxyAdmin.Upgrade(proxyAdminOwnerOpts, cfg.L1Deployments.SystemConfigProxy, storageSetterAddr)
waitForTx(t, tx, err, l1Client) waitForTx(t, tx, err, l1Client)
// Bind a StorageSetter to the SystemConfigProxy address // Bind a StorageSetter to the SystemConfigProxy address
...@@ -554,13 +516,8 @@ func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System ...@@ -554,13 +516,8 @@ func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, currentSlotValue, [32]byte{0}) require.Equal(t, currentSlotValue, [32]byte{0})
// Prepare calldata for SystemConfigProxy -> SystemConfig upgrade
encodedUpgradeCall, err = proxyAdminABI.Pack("upgrade",
cfg.L1Deployments.SystemConfigProxy, cfg.L1Deployments.SystemConfig)
require.NoError(t, err)
// Execute SystemConfigProxy -> SystemConfig upgrade // Execute SystemConfigProxy -> SystemConfig upgrade
tx, err = callViaSafe(safeOwnerOpts, l1Client, proxyAdminOwner, cfg.L1Deployments.ProxyAdmin, encodedUpgradeCall) tx, err = proxyAdmin.Upgrade(proxyAdminOwnerOpts, cfg.L1Deployments.SystemConfigProxy, cfg.L1Deployments.SystemConfig)
waitForTx(t, tx, err, l1Client) waitForTx(t, tx, err, l1Client)
// Reinitialise with existing initializer values but with custom gas token set // Reinitialise with existing initializer values but with custom gas token set
......
...@@ -9,12 +9,6 @@ import { stdJson } from "forge-std/StdJson.sol"; ...@@ -9,12 +9,6 @@ import { stdJson } from "forge-std/StdJson.sol";
import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; import { AlphabetVM } from "test/mocks/AlphabetVM.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
// Safe
import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol";
import { OwnerManager } from "safe-contracts/base/OwnerManager.sol";
import { GnosisSafeProxyFactory as SafeProxyFactory } from "safe-contracts/proxies/GnosisSafeProxyFactory.sol";
import { Enum as SafeOps } from "safe-contracts/common/Enum.sol";
// Scripts // Scripts
import { Deployer } from "scripts/deploy/Deployer.sol"; import { Deployer } from "scripts/deploy/Deployer.sol";
import { Chains } from "scripts/libraries/Chains.sol"; import { Chains } from "scripts/libraries/Chains.sol";
...@@ -196,68 +190,15 @@ contract Deploy is Deployer { ...@@ -196,68 +190,15 @@ contract Deploy is Deployer {
// State Changing Helper Functions // // State Changing Helper Functions //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// @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_) {
if (getAddress("SafeProxyFactory") != address(0)) {
// The SafeProxyFactory is already saved, we can just use it.
safeProxyFactory_ = SafeProxyFactory(getAddress("SafeProxyFactory"));
safeSingleton_ = Safe(getAddress("SafeSingleton"));
return (safeProxyFactory_, safeSingleton_);
}
// These are the 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 Make a call from the Safe contract to an arbitrary address with arbitrary data
function _callViaSafe(Safe _safe, address _target, bytes memory _data) internal {
// This is the signature format used when 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 {
address proxyAdmin = mustGetAddress("ProxyAdmin");
bytes memory data =
abi.encodeCall(IProxyAdmin.upgradeAndCall, (payable(_proxy), _implementation, _innerCallData));
Safe safe = Safe(mustGetAddress("SystemOwnerSafe"));
_callViaSafe({ _safe: safe, _target: proxyAdmin, _data: data });
}
/// @notice Transfer ownership of the ProxyAdmin contract to the final system owner /// @notice Transfer ownership of the ProxyAdmin contract to the final system owner
function transferProxyAdminOwnership() public broadcast { function transferProxyAdminOwnership() public broadcast {
IProxyAdmin proxyAdmin = IProxyAdmin(mustGetAddress("ProxyAdmin")); IProxyAdmin proxyAdmin = IProxyAdmin(mustGetAddress("ProxyAdmin"));
address owner = proxyAdmin.owner(); address owner = proxyAdmin.owner();
address safe = mustGetAddress("SystemOwnerSafe");
if (owner != safe) { address finalSystemOwner = cfg.finalSystemOwner();
proxyAdmin.transferOwnership(safe); if (owner != finalSystemOwner) {
console.log("ProxyAdmin ownership transferred to Safe at: %s", safe); proxyAdmin.transferOwnership(finalSystemOwner);
console.log("ProxyAdmin ownership transferred to final system owner at: %s", finalSystemOwner);
} }
} }
...@@ -334,8 +275,6 @@ contract Deploy is Deployer { ...@@ -334,8 +275,6 @@ contract Deploy is Deployer {
/// @notice Internal function containing the deploy logic. /// @notice Internal function containing the deploy logic.
function _run(bool _needsSuperchain) internal { function _run(bool _needsSuperchain) internal {
console.log("start of L1 Deploy!"); console.log("start of L1 Deploy!");
deploySafe("SystemOwnerSafe");
console.log("deployed Safe!");
// Deploy a new ProxyAdmin and AddressManager // Deploy a new ProxyAdmin and AddressManager
// This proxy will be used on the SuperchainConfig and ProtocolVersions contracts, as well as the contracts // This proxy will be used on the SuperchainConfig and ProtocolVersions contracts, as well as the contracts
...@@ -366,7 +305,6 @@ contract Deploy is Deployer { ...@@ -366,7 +305,6 @@ contract Deploy is Deployer {
function setupAdmin() public { function setupAdmin() public {
deployAddressManager(); deployAddressManager();
deployProxyAdmin(); deployProxyAdmin();
transferProxyAdminOwnership();
} }
/// @notice Deploy a full system with a new SuperchainConfig /// @notice Deploy a full system with a new SuperchainConfig
...@@ -393,7 +331,6 @@ contract Deploy is Deployer { ...@@ -393,7 +331,6 @@ contract Deploy is Deployer {
// Ensure that the requisite contracts are deployed // Ensure that the requisite contracts are deployed
mustGetAddress("SuperchainConfigProxy"); mustGetAddress("SuperchainConfigProxy");
mustGetAddress("SystemOwnerSafe");
mustGetAddress("AddressManager"); mustGetAddress("AddressManager");
mustGetAddress("ProxyAdmin"); mustGetAddress("ProxyAdmin");
...@@ -409,6 +346,7 @@ contract Deploy is Deployer { ...@@ -409,6 +346,7 @@ contract Deploy is Deployer {
transferDisputeGameFactoryOwnership(); transferDisputeGameFactoryOwnership();
transferDelayedWETHOwnership(); transferDelayedWETHOwnership();
transferProxyAdminOwnership();
} }
/// @notice Deploy all of the OP Chain specific contracts /// @notice Deploy all of the OP Chain specific contracts
...@@ -491,70 +429,6 @@ contract Deploy is Deployer { ...@@ -491,70 +429,6 @@ contract Deploy is Deployer {
// Non-Proxied Deployment Functions // // Non-Proxied Deployment Functions //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// @notice Deploy the Safe
function deploySafe(string memory _name) public broadcast returns (address addr_) {
address[] memory owners = new address[](0);
addr_ = deploySafe(_name, owners, 1, true);
}
/// @notice Deploy a new Safe contract. If the keepDeployer option is used to enable further setup actions, then
/// the removeDeployerFromSafe() function should be called on that safe after setup is complete.
/// Note this function does not have the broadcast modifier.
/// @param _name The name of the Safe to deploy.
/// @param _owners The owners of the Safe.
/// @param _threshold The threshold of the Safe.
/// @param _keepDeployer Wether or not the deployer address will be added as an owner of the Safe.
function deploySafe(
string memory _name,
address[] memory _owners,
uint256 _threshold,
bool _keepDeployer
)
public
returns (address addr_)
{
bytes32 salt = keccak256(abi.encode(_name, _implSalt()));
console.log("Deploying safe: %s with salt %s", _name, vm.toString(salt));
(SafeProxyFactory safeProxyFactory, Safe safeSingleton) = _getSafeFactory();
if (_keepDeployer) {
address[] memory expandedOwners = new address[](_owners.length + 1);
// By always adding msg.sender first we know that the previousOwner will be SENTINEL_OWNERS, which makes it
// easier to call removeOwner later.
expandedOwners[0] = msg.sender;
for (uint256 i = 0; i < _owners.length; i++) {
expandedOwners[i + 1] = _owners[i];
}
_owners = expandedOwners;
}
bytes memory initData = abi.encodeCall(
Safe.setup, (_owners, _threshold, address(0), hex"", address(0), address(0), 0, payable(address(0)))
);
addr_ = address(safeProxyFactory.createProxyWithNonce(address(safeSingleton), initData, uint256(salt)));
save(_name, addr_);
console.log("New safe: %s deployed at %s\n Note that this safe is owned by the deployer key", _name, addr_);
}
/// @notice If the keepDeployer option was used with deploySafe(), this function can be used to remove the deployer.
/// Note this function does not have the broadcast modifier.
function removeDeployerFromSafe(string memory _name, uint256 _newThreshold) public {
Safe safe = Safe(mustGetAddress(_name));
// The sentinel address is used to mark the start and end of the linked list of owners in the Safe.
address sentinelOwners = address(0x1);
// Because deploySafe() always adds msg.sender first (if keepDeployer is true), we know that the previousOwner
// will be sentinelOwners.
_callViaSafe({
_safe: safe,
_target: address(safe),
_data: abi.encodeCall(OwnerManager.removeOwner, (sentinelOwners, msg.sender, _newThreshold))
});
console.log("Removed deployer owner from ", _name);
}
/// @notice Deploy the AddressManager /// @notice Deploy the AddressManager
function deployAddressManager() public broadcast returns (address addr_) { function deployAddressManager() public broadcast returns (address addr_) {
console.log("Deploying AddressManager"); console.log("Deploying AddressManager");
...@@ -1025,7 +899,7 @@ contract Deploy is Deployer { ...@@ -1025,7 +899,7 @@ contract Deploy is Deployer {
/// @notice Transfer ownership of the address manager to the ProxyAdmin /// @notice Transfer ownership of the address manager to the ProxyAdmin
function transferAddressManagerOwnership() public broadcast { function transferAddressManagerOwnership() public broadcast {
console.log("Transferring AddressManager ownership to ProxyAdmin"); console.log("Transferring AddressManager ownership to IProxyAdmin");
IAddressManager addressManager = IAddressManager(mustGetAddress("AddressManager")); IAddressManager addressManager = IAddressManager(mustGetAddress("AddressManager"));
address owner = addressManager.owner(); address owner = addressManager.owner();
address proxyAdmin = mustGetAddress("ProxyAdmin"); address proxyAdmin = mustGetAddress("ProxyAdmin");
...@@ -1058,10 +932,12 @@ contract Deploy is Deployer { ...@@ -1058,10 +932,12 @@ contract Deploy is Deployer {
function initializeSuperchainConfig() public broadcast { function initializeSuperchainConfig() public broadcast {
address payable superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address payable superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
address payable superchainConfig = mustGetAddress("SuperchainConfig"); address payable superchainConfig = mustGetAddress("SuperchainConfig");
_upgradeAndCallViaSafe({
IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: superchainConfigProxy, _proxy: superchainConfigProxy,
_implementation: superchainConfig, _implementation: superchainConfig,
_innerCallData: abi.encodeCall(ISuperchainConfig.initialize, (cfg.superchainConfigGuardian(), false)) _data: abi.encodeCall(ISuperchainConfig.initialize, (cfg.superchainConfigGuardian(), false))
}); });
ChainAssertions.checkSuperchainConfig({ _contracts: _proxiesUnstrict(), _cfg: cfg, _isPaused: false }); ChainAssertions.checkSuperchainConfig({ _contracts: _proxiesUnstrict(), _cfg: cfg, _isPaused: false });
...@@ -1073,10 +949,11 @@ contract Deploy is Deployer { ...@@ -1073,10 +949,11 @@ contract Deploy is Deployer {
address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy"); address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy");
address disputeGameFactory = mustGetAddress("DisputeGameFactory"); address disputeGameFactory = mustGetAddress("DisputeGameFactory");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(disputeGameFactoryProxy), _proxy: payable(disputeGameFactoryProxy),
_implementation: disputeGameFactory, _implementation: disputeGameFactory,
_innerCallData: abi.encodeCall(IDisputeGameFactory.initialize, (msg.sender)) _data: abi.encodeCall(IDisputeGameFactory.initialize, (msg.sender))
}); });
string memory version = IDisputeGameFactory(disputeGameFactoryProxy).version(); string memory version = IDisputeGameFactory(disputeGameFactoryProxy).version();
...@@ -1091,10 +968,11 @@ contract Deploy is Deployer { ...@@ -1091,10 +968,11 @@ contract Deploy is Deployer {
address delayedWETH = mustGetAddress("DelayedWETH"); address delayedWETH = mustGetAddress("DelayedWETH");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(delayedWETHProxy), _proxy: payable(delayedWETHProxy),
_implementation: delayedWETH, _implementation: delayedWETH,
_innerCallData: abi.encodeCall(IDelayedWETH.initialize, (msg.sender, ISuperchainConfig(superchainConfigProxy))) _data: abi.encodeCall(IDelayedWETH.initialize, (msg.sender, ISuperchainConfig(superchainConfigProxy)))
}); });
string memory version = IDelayedWETH(payable(delayedWETHProxy)).version(); string memory version = IDelayedWETH(payable(delayedWETHProxy)).version();
...@@ -1114,10 +992,11 @@ contract Deploy is Deployer { ...@@ -1114,10 +992,11 @@ contract Deploy is Deployer {
address delayedWETH = mustGetAddress("DelayedWETH"); address delayedWETH = mustGetAddress("DelayedWETH");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(delayedWETHProxy), _proxy: payable(delayedWETHProxy),
_implementation: delayedWETH, _implementation: delayedWETH,
_innerCallData: abi.encodeCall(IDelayedWETH.initialize, (msg.sender, ISuperchainConfig(superchainConfigProxy))) _data: abi.encodeCall(IDelayedWETH.initialize, (msg.sender, ISuperchainConfig(superchainConfigProxy)))
}); });
string memory version = IDelayedWETH(payable(delayedWETHProxy)).version(); string memory version = IDelayedWETH(payable(delayedWETHProxy)).version();
...@@ -1174,10 +1053,11 @@ contract Deploy is Deployer { ...@@ -1174,10 +1053,11 @@ contract Deploy is Deployer {
}) })
}); });
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(anchorStateRegistryProxy), _proxy: payable(anchorStateRegistryProxy),
_implementation: anchorStateRegistry, _implementation: anchorStateRegistry,
_innerCallData: abi.encodeCall(IAnchorStateRegistry.initialize, (roots, superchainConfig)) _data: abi.encodeCall(IAnchorStateRegistry.initialize, (roots, superchainConfig))
}); });
string memory version = IAnchorStateRegistry(payable(anchorStateRegistryProxy)).version(); string memory version = IAnchorStateRegistry(payable(anchorStateRegistryProxy)).version();
...@@ -1197,10 +1077,11 @@ contract Deploy is Deployer { ...@@ -1197,10 +1077,11 @@ contract Deploy is Deployer {
customGasTokenAddress = cfg.customGasTokenAddress(); customGasTokenAddress = cfg.customGasTokenAddress();
} }
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(systemConfigProxy), _proxy: payable(systemConfigProxy),
_implementation: systemConfig, _implementation: systemConfig,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
ISystemConfig.initialize, ISystemConfig.initialize,
( (
cfg.finalSystemOwner(), cfg.finalSystemOwner(),
...@@ -1242,20 +1123,15 @@ contract Deploy is Deployer { ...@@ -1242,20 +1123,15 @@ contract Deploy is Deployer {
address systemConfigProxy = mustGetAddress("SystemConfigProxy"); address systemConfigProxy = mustGetAddress("SystemConfigProxy");
uint256 proxyType = uint256(proxyAdmin.proxyType(l1StandardBridgeProxy)); uint256 proxyType = uint256(proxyAdmin.proxyType(l1StandardBridgeProxy));
Safe safe = Safe(mustGetAddress("SystemOwnerSafe"));
if (proxyType != uint256(IProxyAdmin.ProxyType.CHUGSPLASH)) { if (proxyType != uint256(IProxyAdmin.ProxyType.CHUGSPLASH)) {
_callViaSafe({ proxyAdmin.setProxyType(l1StandardBridgeProxy, IProxyAdmin.ProxyType.CHUGSPLASH);
_safe: safe,
_target: address(proxyAdmin),
_data: abi.encodeCall(IProxyAdmin.setProxyType, (l1StandardBridgeProxy, IProxyAdmin.ProxyType.CHUGSPLASH))
});
} }
require(uint256(proxyAdmin.proxyType(l1StandardBridgeProxy)) == uint256(IProxyAdmin.ProxyType.CHUGSPLASH)); require(uint256(proxyAdmin.proxyType(l1StandardBridgeProxy)) == uint256(IProxyAdmin.ProxyType.CHUGSPLASH));
_upgradeAndCallViaSafe({ proxyAdmin.upgradeAndCall({
_proxy: payable(l1StandardBridgeProxy), _proxy: payable(l1StandardBridgeProxy),
_implementation: l1StandardBridge, _implementation: l1StandardBridge,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IL1StandardBridge.initialize, IL1StandardBridge.initialize,
( (
ICrossDomainMessenger(l1CrossDomainMessengerProxy), ICrossDomainMessenger(l1CrossDomainMessengerProxy),
...@@ -1279,10 +1155,11 @@ contract Deploy is Deployer { ...@@ -1279,10 +1155,11 @@ contract Deploy is Deployer {
address l1CrossDomainMessengerProxy = mustGetAddress("L1CrossDomainMessengerProxy"); address l1CrossDomainMessengerProxy = mustGetAddress("L1CrossDomainMessengerProxy");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(l1ERC721BridgeProxy), _proxy: payable(l1ERC721BridgeProxy),
_implementation: l1ERC721Bridge, _implementation: l1ERC721Bridge,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IL1ERC721Bridge.initialize, IL1ERC721Bridge.initialize,
(ICrossDomainMessenger(payable(l1CrossDomainMessengerProxy)), ISuperchainConfig(superchainConfigProxy)) (ICrossDomainMessenger(payable(l1CrossDomainMessengerProxy)), ISuperchainConfig(superchainConfigProxy))
) )
...@@ -1302,10 +1179,11 @@ contract Deploy is Deployer { ...@@ -1302,10 +1179,11 @@ contract Deploy is Deployer {
address optimismMintableERC20Factory = mustGetAddress("OptimismMintableERC20Factory"); address optimismMintableERC20Factory = mustGetAddress("OptimismMintableERC20Factory");
address l1StandardBridgeProxy = mustGetAddress("L1StandardBridgeProxy"); address l1StandardBridgeProxy = mustGetAddress("L1StandardBridgeProxy");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(optimismMintableERC20FactoryProxy), _proxy: payable(optimismMintableERC20FactoryProxy),
_implementation: optimismMintableERC20Factory, _implementation: optimismMintableERC20Factory,
_innerCallData: abi.encodeCall(IOptimismMintableERC20Factory.initialize, (l1StandardBridgeProxy)) _data: abi.encodeCall(IOptimismMintableERC20Factory.initialize, (l1StandardBridgeProxy))
}); });
IOptimismMintableERC20Factory factory = IOptimismMintableERC20Factory(optimismMintableERC20FactoryProxy); IOptimismMintableERC20Factory factory = IOptimismMintableERC20Factory(optimismMintableERC20FactoryProxy);
...@@ -1326,36 +1204,25 @@ contract Deploy is Deployer { ...@@ -1326,36 +1204,25 @@ contract Deploy is Deployer {
address systemConfigProxy = mustGetAddress("SystemConfigProxy"); address systemConfigProxy = mustGetAddress("SystemConfigProxy");
uint256 proxyType = uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy)); uint256 proxyType = uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy));
Safe safe = Safe(mustGetAddress("SystemOwnerSafe"));
if (proxyType != uint256(IProxyAdmin.ProxyType.RESOLVED)) { if (proxyType != uint256(IProxyAdmin.ProxyType.RESOLVED)) {
_callViaSafe({ proxyAdmin.setProxyType(l1CrossDomainMessengerProxy, IProxyAdmin.ProxyType.RESOLVED);
_safe: safe,
_target: address(proxyAdmin),
_data: abi.encodeCall(
IProxyAdmin.setProxyType, (l1CrossDomainMessengerProxy, IProxyAdmin.ProxyType.RESOLVED)
)
});
} }
require(uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy)) == uint256(IProxyAdmin.ProxyType.RESOLVED)); require(uint256(proxyAdmin.proxyType(l1CrossDomainMessengerProxy)) == uint256(IProxyAdmin.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))) {
_callViaSafe({ proxyAdmin.setImplementationName(l1CrossDomainMessengerProxy, contractName);
_safe: safe,
_target: address(proxyAdmin),
_data: abi.encodeCall(IProxyAdmin.setImplementationName, (l1CrossDomainMessengerProxy, contractName))
});
} }
require( require(
keccak256(bytes(proxyAdmin.implementationName(l1CrossDomainMessengerProxy))) keccak256(bytes(proxyAdmin.implementationName(l1CrossDomainMessengerProxy)))
== keccak256(bytes(contractName)) == keccak256(bytes(contractName))
); );
_upgradeAndCallViaSafe({ proxyAdmin.upgradeAndCall({
_proxy: payable(l1CrossDomainMessengerProxy), _proxy: payable(l1CrossDomainMessengerProxy),
_implementation: l1CrossDomainMessenger, _implementation: l1CrossDomainMessenger,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IL1CrossDomainMessenger.initialize, IL1CrossDomainMessenger.initialize,
( (
ISuperchainConfig(superchainConfigProxy), ISuperchainConfig(superchainConfigProxy),
...@@ -1378,10 +1245,11 @@ contract Deploy is Deployer { ...@@ -1378,10 +1245,11 @@ contract Deploy is Deployer {
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy"); address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
address l2OutputOracle = mustGetAddress("L2OutputOracle"); address l2OutputOracle = mustGetAddress("L2OutputOracle");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(l2OutputOracleProxy), _proxy: payable(l2OutputOracleProxy),
_implementation: l2OutputOracle, _implementation: l2OutputOracle,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IL2OutputOracle.initialize, IL2OutputOracle.initialize,
( (
cfg.l2OutputOracleSubmissionInterval(), cfg.l2OutputOracleSubmissionInterval(),
...@@ -1416,10 +1284,11 @@ contract Deploy is Deployer { ...@@ -1416,10 +1284,11 @@ contract Deploy is Deployer {
address systemConfigProxy = mustGetAddress("SystemConfigProxy"); address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(optimismPortalProxy), _proxy: payable(optimismPortalProxy),
_implementation: optimismPortal, _implementation: optimismPortal,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IOptimismPortal.initialize, IOptimismPortal.initialize,
( (
IL2OutputOracle(l2OutputOracleProxy), IL2OutputOracle(l2OutputOracleProxy),
...@@ -1445,10 +1314,11 @@ contract Deploy is Deployer { ...@@ -1445,10 +1314,11 @@ contract Deploy is Deployer {
address systemConfigProxy = mustGetAddress("SystemConfigProxy"); address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(optimismPortalProxy), _proxy: payable(optimismPortalProxy),
_implementation: optimismPortal2, _implementation: optimismPortal2,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IOptimismPortal2.initialize, IOptimismPortal2.initialize,
( (
IDisputeGameFactory(disputeGameFactoryProxy), IDisputeGameFactory(disputeGameFactoryProxy),
...@@ -1475,10 +1345,11 @@ contract Deploy is Deployer { ...@@ -1475,10 +1345,11 @@ contract Deploy is Deployer {
uint256 requiredProtocolVersion = cfg.requiredProtocolVersion(); uint256 requiredProtocolVersion = cfg.requiredProtocolVersion();
uint256 recommendedProtocolVersion = cfg.recommendedProtocolVersion(); uint256 recommendedProtocolVersion = cfg.recommendedProtocolVersion();
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(protocolVersionsProxy), _proxy: payable(protocolVersionsProxy),
_implementation: protocolVersions, _implementation: protocolVersions,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IProtocolVersions.initialize, IProtocolVersions.initialize,
( (
finalSystemOwner, finalSystemOwner,
...@@ -1500,13 +1371,13 @@ contract Deploy is Deployer { ...@@ -1500,13 +1371,13 @@ contract Deploy is Deployer {
console.log("Transferring DisputeGameFactory ownership to Safe"); console.log("Transferring DisputeGameFactory ownership to Safe");
IDisputeGameFactory disputeGameFactory = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy")); IDisputeGameFactory disputeGameFactory = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
address owner = disputeGameFactory.owner(); address owner = disputeGameFactory.owner();
address finalSystemOwner = cfg.finalSystemOwner();
address safe = mustGetAddress("SystemOwnerSafe"); if (owner != finalSystemOwner) {
if (owner != safe) { disputeGameFactory.transferOwnership(finalSystemOwner);
disputeGameFactory.transferOwnership(safe); console.log("DisputeGameFactory ownership transferred to final system owner at: %s", finalSystemOwner);
console.log("DisputeGameFactory ownership transferred to Safe at: %s", safe);
} }
ChainAssertions.checkDisputeGameFactory({ _contracts: _proxies(), _expectedOwner: safe }); ChainAssertions.checkDisputeGameFactory({ _contracts: _proxies(), _expectedOwner: finalSystemOwner });
} }
/// @notice Transfer ownership of the DelayedWETH contract to the final system owner /// @notice Transfer ownership of the DelayedWETH contract to the final system owner
...@@ -1515,12 +1386,17 @@ contract Deploy is Deployer { ...@@ -1515,12 +1386,17 @@ contract Deploy is Deployer {
IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy")); IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy"));
address owner = weth.owner(); address owner = weth.owner();
address safe = mustGetAddress("SystemOwnerSafe"); address finalSystemOwner = cfg.finalSystemOwner();
if (owner != safe) { if (owner != finalSystemOwner) {
weth.transferOwnership(safe); weth.transferOwnership(finalSystemOwner);
console.log("DelayedWETH ownership transferred to Safe at: %s", safe); console.log("DelayedWETH ownership transferred to final system owner at: %s", finalSystemOwner);
} }
ChainAssertions.checkDelayedWETH({ _contracts: _proxies(), _cfg: cfg, _isProxy: true, _expectedOwner: safe }); ChainAssertions.checkDelayedWETH({
_contracts: _proxies(),
_cfg: cfg,
_isProxy: true,
_expectedOwner: finalSystemOwner
});
} }
/// @notice Transfer ownership of the permissioned DelayedWETH contract to the final system owner /// @notice Transfer ownership of the permissioned DelayedWETH contract to the final system owner
...@@ -1529,16 +1405,16 @@ contract Deploy is Deployer { ...@@ -1529,16 +1405,16 @@ contract Deploy is Deployer {
IDelayedWETH weth = IDelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy")); IDelayedWETH weth = IDelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy"));
address owner = weth.owner(); address owner = weth.owner();
address safe = mustGetAddress("SystemOwnerSafe"); address finalSystemOwner = cfg.finalSystemOwner();
if (owner != safe) { if (owner != finalSystemOwner) {
weth.transferOwnership(safe); weth.transferOwnership(finalSystemOwner);
console.log("DelayedWETH ownership transferred to Safe at: %s", safe); console.log("DelayedWETH ownership transferred to final system owner at: %s", finalSystemOwner);
} }
ChainAssertions.checkPermissionedDelayedWETH({ ChainAssertions.checkPermissionedDelayedWETH({
_contracts: _proxies(), _contracts: _proxies(),
_cfg: cfg, _cfg: cfg,
_isProxy: true, _isProxy: true,
_expectedOwner: safe _expectedOwner: finalSystemOwner
}); });
} }
...@@ -1812,10 +1688,11 @@ contract Deploy is Deployer { ...@@ -1812,10 +1688,11 @@ contract Deploy is Deployer {
uint256 daBondSize = cfg.daBondSize(); uint256 daBondSize = cfg.daBondSize();
uint256 daResolverRefundPercentage = cfg.daResolverRefundPercentage(); uint256 daResolverRefundPercentage = cfg.daResolverRefundPercentage();
_upgradeAndCallViaSafe({ IProxyAdmin proxyAdmin = IProxyAdmin(payable(mustGetAddress("ProxyAdmin")));
proxyAdmin.upgradeAndCall({
_proxy: payable(dataAvailabilityChallengeProxy), _proxy: payable(dataAvailabilityChallengeProxy),
_implementation: dataAvailabilityChallenge, _implementation: dataAvailabilityChallenge,
_innerCallData: abi.encodeCall( _data: abi.encodeCall(
IDataAvailabilityChallenge.initialize, IDataAvailabilityChallenge.initialize,
(finalSystemOwner, daChallengeWindow, daResolveWindow, daBondSize, daResolverRefundPercentage) (finalSystemOwner, daChallengeWindow, daResolveWindow, daBondSize, daResolverRefundPercentage)
) )
......
...@@ -5,9 +5,11 @@ import { console2 as console } from "forge-std/console2.sol"; ...@@ -5,9 +5,11 @@ import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.sol"; import { stdJson } from "forge-std/StdJson.sol";
import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol"; import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol";
import { GnosisSafeProxyFactory as SafeProxyFactory } from "safe-contracts/proxies/GnosisSafeProxyFactory.sol";
import { OwnerManager } from "safe-contracts/base/OwnerManager.sol"; import { OwnerManager } from "safe-contracts/base/OwnerManager.sol";
import { ModuleManager } from "safe-contracts/base/ModuleManager.sol"; import { ModuleManager } from "safe-contracts/base/ModuleManager.sol";
import { GuardManager } from "safe-contracts/base/GuardManager.sol"; import { GuardManager } from "safe-contracts/base/GuardManager.sol";
import { Enum as SafeOps } from "safe-contracts/common/Enum.sol";
import { Deployer } from "scripts/deploy/Deployer.sol"; import { Deployer } from "scripts/deploy/Deployer.sol";
...@@ -17,8 +19,8 @@ import { DeputyGuardianModule } from "src/safe/DeputyGuardianModule.sol"; ...@@ -17,8 +19,8 @@ import { DeputyGuardianModule } from "src/safe/DeputyGuardianModule.sol";
import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";
import { Deploy } from "./Deploy.s.sol"; import { Deploy } from "./Deploy.s.sol";
/// @notice Configuration for a Safe /// @notice Configuration for a Safe
struct SafeConfig { struct SafeConfig {
uint256 threshold; uint256 threshold;
address[] owners; address[] owners;
...@@ -50,7 +52,7 @@ struct GuardianConfig { ...@@ -50,7 +52,7 @@ struct GuardianConfig {
DeputyGuardianModuleConfig deputyGuardianModuleConfig; DeputyGuardianModuleConfig deputyGuardianModuleConfig;
} }
/// @title Deploy /// @title DeployOwnership
/// @notice Script used to deploy and configure the Safe contracts which are used to manage the Superchain, /// @notice Script used to deploy and configure the Safe contracts which are used to manage the Superchain,
/// as the ProxyAdminOwner and other roles in the system. Note that this script is not executable in a /// as the ProxyAdminOwner and other roles in the system. Note that this script is not executable in a
/// production environment as some steps depend on having a quorum of signers available. This script is meant to /// production environment as some steps depend on having a quorum of signers available. This script is meant to
...@@ -112,6 +114,113 @@ contract DeployOwnership is Deploy { ...@@ -112,6 +114,113 @@ contract DeployOwnership is Deploy {
}); });
} }
/// @notice Make a call from the Safe contract to an arbitrary address with arbitrary data
function _callViaSafe(Safe _safe, address _target, bytes memory _data) internal {
// This is the signature format used when 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 Deploy the Safe
function deploySafe(string memory _name) public broadcast returns (address addr_) {
address[] memory owners = new address[](0);
addr_ = deploySafe(_name, owners, 1, true);
}
/// @notice Deploy a new Safe contract. If the keepDeployer option is used to enable further setup actions, then
/// the removeDeployerFromSafe() function should be called on that safe after setup is complete.
/// Note this function does not have the broadcast modifier.
/// @param _name The name of the Safe to deploy.
/// @param _owners The owners of the Safe.
/// @param _threshold The threshold of the Safe.
/// @param _keepDeployer Wether or not the deployer address will be added as an owner of the Safe.
function deploySafe(
string memory _name,
address[] memory _owners,
uint256 _threshold,
bool _keepDeployer
)
public
returns (address addr_)
{
bytes32 salt = keccak256(abi.encode(_name, _implSalt()));
console.log("Deploying safe: %s with salt %s", _name, vm.toString(salt));
(SafeProxyFactory safeProxyFactory, Safe safeSingleton) = _getSafeFactory();
if (_keepDeployer) {
address[] memory expandedOwners = new address[](_owners.length + 1);
// By always adding msg.sender first we know that the previousOwner will be SENTINEL_OWNERS, which makes it
// easier to call removeOwner later.
expandedOwners[0] = msg.sender;
for (uint256 i = 0; i < _owners.length; i++) {
expandedOwners[i + 1] = _owners[i];
}
_owners = expandedOwners;
}
bytes memory initData = abi.encodeCall(
Safe.setup, (_owners, _threshold, address(0), hex"", address(0), address(0), 0, payable(address(0)))
);
addr_ = address(safeProxyFactory.createProxyWithNonce(address(safeSingleton), initData, uint256(salt)));
save(_name, addr_);
console.log("New safe: %s deployed at %s\n Note that this safe is owned by the deployer key", _name, addr_);
}
/// @notice If the keepDeployer option was used with deploySafe(), this function can be used to remove the deployer.
/// Note this function does not have the broadcast modifier.
function removeDeployerFromSafe(string memory _name, uint256 _newThreshold) public {
Safe safe = Safe(mustGetAddress(_name));
// The sentinel address is used to mark the start and end of the linked list of owners in the Safe.
address sentinelOwners = address(0x1);
// Because deploySafe() always adds msg.sender first (if keepDeployer is true), we know that the previousOwner
// will be sentinelOwners.
_callViaSafe({
_safe: safe,
_target: address(safe),
_data: abi.encodeCall(OwnerManager.removeOwner, (sentinelOwners, msg.sender, _newThreshold))
});
console.log("Removed deployer owner from ", _name);
}
/// @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_) {
if (getAddress("SafeProxyFactory") != address(0)) {
// The SafeProxyFactory is already saved, we can just use it.
safeProxyFactory_ = SafeProxyFactory(getAddress("SafeProxyFactory"));
safeSingleton_ = Safe(getAddress("SafeSingleton"));
return (safeProxyFactory_, safeSingleton_);
}
// These are the 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 Deploys a Safe with a configuration similar to that of the Foundation Safe on Mainnet. /// @notice Deploys a Safe with a configuration similar to that of the Foundation Safe on Mainnet.
function deployFoundationOperationsSafe() public broadcast returns (address addr_) { function deployFoundationOperationsSafe() public broadcast returns (address addr_) {
SafeConfig memory exampleFoundationConfig = _getExampleFoundationConfig(); SafeConfig memory exampleFoundationConfig = _getExampleFoundationConfig();
......
...@@ -22,11 +22,11 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -22,11 +22,11 @@ contract FPACOPS is Deploy, StdAssertions {
// ENTRYPOINTS // // ENTRYPOINTS //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
function deployFPAC(address _proxyAdmin, address _systemOwnerSafe, address _superchainConfigProxy) public { function deployFPAC(address _proxyAdmin, address _finalSystemOwner, address _superchainConfigProxy) public {
console.log("Deploying a fresh FPAC system and OptimismPortal2 implementation."); console.log("Deploying a fresh FPAC system and OptimismPortal2 implementation.");
prankDeployment("ProxyAdmin", msg.sender); prankDeployment("ProxyAdmin", msg.sender);
prankDeployment("SystemOwnerSafe", msg.sender); prankDeployment("FinalSystemOwner", msg.sender);
prankDeployment("SuperchainConfigProxy", _superchainConfigProxy); prankDeployment("SuperchainConfigProxy", _superchainConfigProxy);
// Deploy the proxies. // Deploy the proxies.
...@@ -54,14 +54,14 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -54,14 +54,14 @@ contract FPACOPS is Deploy, StdAssertions {
// Deploy the Permissioned Cannon Fault game implementation and set it as game ID = 1. // Deploy the Permissioned Cannon Fault game implementation and set it as game ID = 1.
setPermissionedCannonFaultGameImplementation({ _allowUpgrade: false }); setPermissionedCannonFaultGameImplementation({ _allowUpgrade: false });
// Transfer ownership of the DisputeGameFactory to the SystemOwnerSafe, and transfer the administrative rights // Transfer ownership of the DisputeGameFactory to the FinalSystemOwner, and transfer the administrative rights
// of the DisputeGameFactoryProxy to the ProxyAdmin. // of the DisputeGameFactoryProxy to the ProxyAdmin.
transferDGFOwnershipFinal({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe }); transferDGFOwnershipFinal({ _proxyAdmin: _proxyAdmin, _finalSystemOwner: _finalSystemOwner });
transferWethOwnershipFinal({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe }); transferWethOwnershipFinal({ _proxyAdmin: _proxyAdmin, _finalSystemOwner: _finalSystemOwner });
transferAnchorStateOwnershipFinal({ _proxyAdmin: _proxyAdmin }); transferAnchorStateOwnershipFinal({ _proxyAdmin: _proxyAdmin });
// Run post-deployment assertions. // Run post-deployment assertions.
postDeployAssertions({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe }); postDeployAssertions({ _proxyAdmin: _proxyAdmin, _finalSystemOwner: _finalSystemOwner });
// Print overview // Print overview
printConfigReview(); printConfigReview();
...@@ -126,12 +126,12 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -126,12 +126,12 @@ contract FPACOPS is Deploy, StdAssertions {
} }
/// @notice Transfers admin rights of the `DisputeGameFactoryProxy` to the `ProxyAdmin` and sets the /// @notice Transfers admin rights of the `DisputeGameFactoryProxy` to the `ProxyAdmin` and sets the
/// `DisputeGameFactory` owner to the `SystemOwnerSafe`. /// `DisputeGameFactory` owner to the `FinalSystemOwner`.
function transferDGFOwnershipFinal(address _proxyAdmin, address _systemOwnerSafe) internal broadcast { function transferDGFOwnershipFinal(address _proxyAdmin, address _finalSystemOwner) internal broadcast {
IDisputeGameFactory dgf = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy")); IDisputeGameFactory dgf = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
// Transfer the ownership of the DisputeGameFactory to the SystemOwnerSafe. // Transfer the ownership of the DisputeGameFactory to the FinalSystemOwner.
dgf.transferOwnership(_systemOwnerSafe); dgf.transferOwnership(_finalSystemOwner);
// Transfer the admin rights of the DisputeGameFactoryProxy to the ProxyAdmin. // Transfer the admin rights of the DisputeGameFactoryProxy to the ProxyAdmin.
IProxy prox = IProxy(payable(address(dgf))); IProxy prox = IProxy(payable(address(dgf)));
...@@ -139,12 +139,12 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -139,12 +139,12 @@ contract FPACOPS is Deploy, StdAssertions {
} }
/// @notice Transfers admin rights of the `DelayedWETHProxy` to the `ProxyAdmin` and sets the /// @notice Transfers admin rights of the `DelayedWETHProxy` to the `ProxyAdmin` and sets the
/// `DelayedWETH` owner to the `SystemOwnerSafe`. /// `DelayedWETH` owner to the `FinalSystemOwner`.
function transferWethOwnershipFinal(address _proxyAdmin, address _systemOwnerSafe) internal broadcast { function transferWethOwnershipFinal(address _proxyAdmin, address _finalSystemOwner) internal broadcast {
IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy")); IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy"));
// Transfer the ownership of the DelayedWETH to the SystemOwnerSafe. // Transfer the ownership of the DelayedWETH to the FinalSystemOwner.
weth.transferOwnership(_systemOwnerSafe); weth.transferOwnership(_finalSystemOwner);
// Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin. // Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin.
IProxy prox = IProxy(payable(address(weth))); IProxy prox = IProxy(payable(address(weth)));
...@@ -161,7 +161,7 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -161,7 +161,7 @@ contract FPACOPS is Deploy, StdAssertions {
} }
/// @notice Checks that the deployed system is configured correctly. /// @notice Checks that the deployed system is configured correctly.
function postDeployAssertions(address _proxyAdmin, address _systemOwnerSafe) internal view { function postDeployAssertions(address _proxyAdmin, address _finalSystemOwner) internal view {
Types.ContractSet memory contracts = _proxiesUnstrict(); Types.ContractSet memory contracts = _proxiesUnstrict();
contracts.OptimismPortal2 = mustGetAddress("OptimismPortal2"); contracts.OptimismPortal2 = mustGetAddress("OptimismPortal2");
...@@ -172,10 +172,10 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -172,10 +172,10 @@ contract FPACOPS is Deploy, StdAssertions {
address dgfProxyAddr = mustGetAddress("DisputeGameFactoryProxy"); address dgfProxyAddr = mustGetAddress("DisputeGameFactoryProxy");
IDisputeGameFactory dgfProxy = IDisputeGameFactory(dgfProxyAddr); IDisputeGameFactory dgfProxy = IDisputeGameFactory(dgfProxyAddr);
assertEq(address(uint160(uint256(vm.load(dgfProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin); assertEq(address(uint160(uint256(vm.load(dgfProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin);
ChainAssertions.checkDisputeGameFactory(contracts, _systemOwnerSafe); ChainAssertions.checkDisputeGameFactory(contracts, _finalSystemOwner);
address wethProxyAddr = mustGetAddress("DelayedWETHProxy"); address wethProxyAddr = mustGetAddress("DelayedWETHProxy");
assertEq(address(uint160(uint256(vm.load(wethProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin); assertEq(address(uint160(uint256(vm.load(wethProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin);
ChainAssertions.checkDelayedWETH(contracts, cfg, true, _systemOwnerSafe); ChainAssertions.checkDelayedWETH(contracts, cfg, true, _finalSystemOwner);
// Check the config elements in the deployed contracts. // Check the config elements in the deployed contracts.
ChainAssertions.checkOptimismPortal2(contracts, cfg, false); ChainAssertions.checkOptimismPortal2(contracts, cfg, false);
......
...@@ -30,13 +30,13 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -30,13 +30,13 @@ contract FPACOPS2 is Deploy, StdAssertions {
/// AnchorStateRegistry. Does not deploy a new DisputeGameFactory. System /// AnchorStateRegistry. Does not deploy a new DisputeGameFactory. System
/// Owner is responsible for updating implementations later. /// Owner is responsible for updating implementations later.
/// @param _proxyAdmin Address of the ProxyAdmin contract to transfer ownership to. /// @param _proxyAdmin Address of the ProxyAdmin contract to transfer ownership to.
/// @param _systemOwnerSafe Address of the SystemOwner. /// @param _finalSystemOwner Address of the SystemOwner.
/// @param _superchainConfigProxy Address of the SuperchainConfig proxy contract. /// @param _superchainConfigProxy Address of the SuperchainConfig proxy contract.
/// @param _disputeGameFactoryProxy Address of the DisputeGameFactory proxy contract. /// @param _disputeGameFactoryProxy Address of the DisputeGameFactory proxy contract.
/// @param _anchorStateRegistryProxy Address of the AnchorStateRegistry proxy contract. /// @param _anchorStateRegistryProxy Address of the AnchorStateRegistry proxy contract.
function deployFPAC2( function deployFPAC2(
address _proxyAdmin, address _proxyAdmin,
address _systemOwnerSafe, address _finalSystemOwner,
address _superchainConfigProxy, address _superchainConfigProxy,
address _disputeGameFactoryProxy, address _disputeGameFactoryProxy,
address _anchorStateRegistryProxy address _anchorStateRegistryProxy
...@@ -47,7 +47,7 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -47,7 +47,7 @@ contract FPACOPS2 is Deploy, StdAssertions {
// Prank required deployments. // Prank required deployments.
prankDeployment("ProxyAdmin", msg.sender); prankDeployment("ProxyAdmin", msg.sender);
prankDeployment("SystemOwnerSafe", msg.sender); prankDeployment("FinalSystemOwner", msg.sender);
prankDeployment("SuperchainConfigProxy", _superchainConfigProxy); prankDeployment("SuperchainConfigProxy", _superchainConfigProxy);
prankDeployment("DisputeGameFactoryProxy", _disputeGameFactoryProxy); prankDeployment("DisputeGameFactoryProxy", _disputeGameFactoryProxy);
prankDeployment("AnchorStateRegistryProxy", _anchorStateRegistryProxy); prankDeployment("AnchorStateRegistryProxy", _anchorStateRegistryProxy);
...@@ -71,11 +71,11 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -71,11 +71,11 @@ contract FPACOPS2 is Deploy, StdAssertions {
deployPermissionedDisputeGame(); deployPermissionedDisputeGame();
// Transfer ownership of DelayedWETH to ProxyAdmin. // Transfer ownership of DelayedWETH to ProxyAdmin.
transferWethOwnershipFinal({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe }); transferWethOwnershipFinal({ _proxyAdmin: _proxyAdmin, _finalSystemOwner: _finalSystemOwner });
transferPermissionedWETHOwnershipFinal({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe }); transferPermissionedWETHOwnershipFinal({ _proxyAdmin: _proxyAdmin, _finalSystemOwner: _finalSystemOwner });
// Run post-deployment assertions. // Run post-deployment assertions.
postDeployAssertions({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe }); postDeployAssertions({ _proxyAdmin: _proxyAdmin, _finalSystemOwner: _finalSystemOwner });
// Print overview. // Print overview.
printConfigReview(); printConfigReview();
...@@ -169,14 +169,14 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -169,14 +169,14 @@ contract FPACOPS2 is Deploy, StdAssertions {
} }
/// @notice Transfers admin rights of the `DelayedWETHProxy` to the `ProxyAdmin` and sets the /// @notice Transfers admin rights of the `DelayedWETHProxy` to the `ProxyAdmin` and sets the
/// `DelayedWETH` owner to the `SystemOwnerSafe`. /// `DelayedWETH` owner to the `FinalSystemOwner`.
function transferWethOwnershipFinal(address _proxyAdmin, address _systemOwnerSafe) internal broadcast { function transferWethOwnershipFinal(address _proxyAdmin, address _finalSystemOwner) internal broadcast {
console.log("Transferring ownership of DelayedWETHProxy"); console.log("Transferring ownership of DelayedWETHProxy");
IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy")); IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy"));
// Transfer the ownership of the DelayedWETH to the SystemOwnerSafe. // Transfer the ownership of the DelayedWETH to the FinalSystemOwner.
weth.transferOwnership(_systemOwnerSafe); weth.transferOwnership(_finalSystemOwner);
// Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin. // Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin.
IProxy prox = IProxy(payable(address(weth))); IProxy prox = IProxy(payable(address(weth)));
...@@ -184,14 +184,20 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -184,14 +184,20 @@ contract FPACOPS2 is Deploy, StdAssertions {
} }
/// @notice Transfers admin rights of the permissioned `DelayedWETHProxy` to the `ProxyAdmin` /// @notice Transfers admin rights of the permissioned `DelayedWETHProxy` to the `ProxyAdmin`
/// and sets the `DelayedWETH` owner to the `SystemOwnerSafe`. /// and sets the `DelayedWETH` owner to the `FinalSystemOwner`.
function transferPermissionedWETHOwnershipFinal(address _proxyAdmin, address _systemOwnerSafe) internal broadcast { function transferPermissionedWETHOwnershipFinal(
address _proxyAdmin,
address _finalSystemOwner
)
internal
broadcast
{
console.log("Transferring ownership of permissioned DelayedWETHProxy"); console.log("Transferring ownership of permissioned DelayedWETHProxy");
IDelayedWETH weth = IDelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy")); IDelayedWETH weth = IDelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy"));
// Transfer the ownership of the DelayedWETH to the SystemOwnerSafe. // Transfer the ownership of the DelayedWETH to the FinalSystemOwner.
weth.transferOwnership(_systemOwnerSafe); weth.transferOwnership(_finalSystemOwner);
// Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin. // Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin.
IProxy prox = IProxy(payable(address(weth))); IProxy prox = IProxy(payable(address(weth)));
...@@ -199,7 +205,7 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -199,7 +205,7 @@ contract FPACOPS2 is Deploy, StdAssertions {
} }
/// @notice Checks that the deployed system is configured correctly. /// @notice Checks that the deployed system is configured correctly.
function postDeployAssertions(address _proxyAdmin, address _systemOwnerSafe) internal view { function postDeployAssertions(address _proxyAdmin, address _finalSystemOwner) internal view {
Types.ContractSet memory contracts = _proxiesUnstrict(); Types.ContractSet memory contracts = _proxiesUnstrict();
// Ensure that `useFaultProofs` is set to `true`. // Ensure that `useFaultProofs` is set to `true`.
...@@ -218,9 +224,9 @@ contract FPACOPS2 is Deploy, StdAssertions { ...@@ -218,9 +224,9 @@ contract FPACOPS2 is Deploy, StdAssertions {
assertEq(address(uint160(uint256(vm.load(soyWethProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin); assertEq(address(uint160(uint256(vm.load(soyWethProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin);
// Run standard assertions for DGF and DelayedWETH. // Run standard assertions for DGF and DelayedWETH.
ChainAssertions.checkDisputeGameFactory(contracts, _systemOwnerSafe); ChainAssertions.checkDisputeGameFactory(contracts, _finalSystemOwner);
ChainAssertions.checkDelayedWETH(contracts, cfg, true, _systemOwnerSafe); ChainAssertions.checkDelayedWETH(contracts, cfg, true, _finalSystemOwner);
ChainAssertions.checkPermissionedDelayedWETH(contracts, cfg, true, _systemOwnerSafe); ChainAssertions.checkPermissionedDelayedWETH(contracts, cfg, true, _finalSystemOwner);
// Verify PreimageOracle configuration. // Verify PreimageOracle configuration.
IPreimageOracle oracle = IPreimageOracle(mustGetAddress("PreimageOracle")); IPreimageOracle oracle = IPreimageOracle(mustGetAddress("PreimageOracle"));
......
...@@ -23,9 +23,9 @@ cannon-prestate: # Generate the cannon prestate, and tar the `op-program` + `can ...@@ -23,9 +23,9 @@ cannon-prestate: # Generate the cannon prestate, and tar the `op-program` + `can
.PHONY: deploy-fresh .PHONY: deploy-fresh
deploy-fresh: cannon-prestate # Deploy a fresh version of the FPAC contracts. Pass `--broadcast` to send to the network. deploy-fresh: cannon-prestate # Deploy a fresh version of the FPAC contracts. Pass `--broadcast` to send to the network.
forge script FPACOPS.s.sol --sig "deployFPAC(address,address,address)" $(proxy-admin) $(system-owner-safe) $(superchain-config-proxy) --chain $(chain) -vvv $(args) forge script FPACOPS.s.sol --sig "deployFPAC(address,address,address)" $(proxy-admin) $(final-system-owner) $(superchain-config-proxy) --chain $(chain) -vvv $(args)
# TODO: Convert this whole file to a justfile # TODO: Convert this whole file to a justfile
.PHONY: deploy-upgrade .PHONY: deploy-upgrade
deploy-upgrade: cannon-prestate # Deploy upgraded FP contracts. Pass `--broadcast` to send to the network. deploy-upgrade: cannon-prestate # Deploy upgraded FP contracts. Pass `--broadcast` to send to the network.
forge script FPACOPS2.s.sol --sig "deployFPAC2(address,address,address,address,address)" $(proxy-admin) $(system-owner-safe) $(superchain-config-proxy) $(dispute-game-factory-proxy) $(anchor-state-registry-proxy) --chain $(chain) -vvv $(args) forge script FPACOPS2.s.sol --sig "deployFPAC2(address,address,address,address,address)" $(proxy-admin) $(final-system-owner) $(superchain-config-proxy) $(dispute-game-factory-proxy) $(anchor-state-registry-proxy) --chain $(chain) -vvv $(args)
...@@ -17,5 +17,5 @@ make cannon-prestate chain=<chain-name> ...@@ -17,5 +17,5 @@ make cannon-prestate chain=<chain-name>
_Description_: Deploys a fully fresh FPAC system to the passed chain. All args after the `args=` are forwarded to `forge script`. _Description_: Deploys a fully fresh FPAC system to the passed chain. All args after the `args=` are forwarded to `forge script`.
```sh ```sh
make deploy-fresh chain=<chain-name> proxy-admin=<chain-proxy-admin-addr> system-owner-safe=<chain-safe-addr> [args=<forge-script-args>] make deploy-fresh chain=<chain-name> proxy-admin=<chain-proxy-admin-addr> final-system-owner=<chain-safe-addr> [args=<forge-script-args>]
``` ```
...@@ -22,7 +22,7 @@ contract DelayedWETH_Init is CommonTest { ...@@ -22,7 +22,7 @@ contract DelayedWETH_Init is CommonTest {
super.setUp(); super.setUp();
// Transfer ownership of delayed WETH to the test contract. // Transfer ownership of delayed WETH to the test contract.
vm.prank(deploy.mustGetAddress("SystemOwnerSafe")); vm.prank(delayedWeth.owner());
delayedWeth.transferOwnership(address(this)); delayedWeth.transferOwnership(address(this));
} }
} }
......
...@@ -29,7 +29,7 @@ contract DisputeGameFactory_Init is CommonTest { ...@@ -29,7 +29,7 @@ contract DisputeGameFactory_Init is CommonTest {
fakeClone = new FakeClone(); fakeClone = new FakeClone();
// Transfer ownership of the factory to the test contract. // Transfer ownership of the factory to the test contract.
vm.prank(deploy.mustGetAddress("SystemOwnerSafe")); vm.prank(disputeGameFactory.owner());
disputeGameFactory.transferOwnership(address(this)); disputeGameFactory.transferOwnership(address(this));
} }
} }
......
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