diff --git a/packages/contracts-bedrock/interfaces/L2/IBaseFeeVault.sol b/packages/contracts-bedrock/interfaces/L2/IBaseFeeVault.sol index ac94212337a..2c6c51ea631 100644 --- a/packages/contracts-bedrock/interfaces/L2/IBaseFeeVault.sol +++ b/packages/contracts-bedrock/interfaces/L2/IBaseFeeVault.sol @@ -6,6 +6,10 @@ import { Types } from "src/libraries/Types.sol"; interface IBaseFeeVault { error FeeVault_OnlyProxyAdminOwner(); + error InvalidInitialization(); + error NotInitializing(); + + event Initialized(uint64 version); event Withdrawal(uint256 value, address to, address from); event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount); @@ -16,6 +20,12 @@ interface IBaseFeeVault { receive() external payable; + function initialize( + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + external; function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); @@ -29,11 +39,4 @@ interface IBaseFeeVault { function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external; function version() external view returns (string memory); - - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; } diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol b/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol index ea60baca1df..96f8a668793 100644 --- a/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol +++ b/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol @@ -5,6 +5,10 @@ import { Types } from "src/libraries/Types.sol"; interface IFeeVault { error FeeVault_OnlyProxyAdminOwner(); + error InvalidInitialization(); + error NotInitializing(); + + event Initialized(uint64 version); event Withdrawal(uint256 value, address to, address from); event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); @@ -16,6 +20,12 @@ interface IFeeVault { receive() external payable; + function initialize( + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + external; function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); @@ -30,15 +40,3 @@ interface IFeeVault { function __constructor__() external; } - -interface IFeeVaultConstructor { - /// NOTE: This is the real constructor for the FeeVault contract, but can't be added to the main interface because - /// it is an abstract contract, and on the scripts it gets an empty constructor automatically generated that - /// makes the `interfaces-check` script fail. - function __constructor__( - address __recipient, - uint256 __minWithdrawalAmount, - Types.WithdrawalNetwork __withdrawalNetwork - ) - external; -} diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol b/packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol deleted file mode 100644 index da5d6debe84..00000000000 --- a/packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import { Types } from "src/libraries/Types.sol"; - -interface IFeeVaultInitializer { - /// @notice Emitted when a fee vault implementation is deployed. - /// @param vaultType The type of fee vault being deployed. - /// @param newImplementation The deployed implementation address. - /// @param recipient The recipient address for the implementation. - /// @param network The withdrawal network for the implementation. - /// @param minWithdrawalAmount The minimum withdrawal amount for the implementation. - event FeeVaultDeployed( - string indexed vaultType, - address indexed newImplementation, - address recipient, - Types.WithdrawalNetwork network, - uint256 minWithdrawalAmount - ); - - function version() external view returns (string memory); -} \ No newline at end of file diff --git a/packages/contracts-bedrock/interfaces/L2/IL1FeeVault.sol b/packages/contracts-bedrock/interfaces/L2/IL1FeeVault.sol index 6377a0c1908..6da52552c37 100644 --- a/packages/contracts-bedrock/interfaces/L2/IL1FeeVault.sol +++ b/packages/contracts-bedrock/interfaces/L2/IL1FeeVault.sol @@ -6,6 +6,10 @@ import { Types } from "src/libraries/Types.sol"; interface IL1FeeVault { error FeeVault_OnlyProxyAdminOwner(); + error InvalidInitialization(); + error NotInitializing(); + + event Initialized(uint64 version); event Withdrawal(uint256 value, address to, address from); event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount); @@ -16,6 +20,12 @@ interface IL1FeeVault { receive() external payable; + function initialize( + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + external; function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); @@ -29,11 +39,4 @@ interface IL1FeeVault { function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external; function version() external view returns (string memory); - - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; } diff --git a/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol b/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol index 4829cb223eb..fe2789ca968 100644 --- a/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol +++ b/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol @@ -6,6 +6,10 @@ import { Types } from "src/libraries/Types.sol"; interface IOperatorFeeVault { error FeeVault_OnlyProxyAdminOwner(); + error InvalidInitialization(); + error NotInitializing(); + + event Initialized(uint64 version); event Withdrawal(uint256 value, address to, address from); event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount); @@ -16,6 +20,12 @@ interface IOperatorFeeVault { receive() external payable; + function initialize( + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + external; function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); @@ -29,11 +39,4 @@ interface IOperatorFeeVault { function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external; function version() external view returns (string memory); - - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; } diff --git a/packages/contracts-bedrock/interfaces/L2/ISequencerFeeVault.sol b/packages/contracts-bedrock/interfaces/L2/ISequencerFeeVault.sol index f99fbb7e865..1770b5126bf 100644 --- a/packages/contracts-bedrock/interfaces/L2/ISequencerFeeVault.sol +++ b/packages/contracts-bedrock/interfaces/L2/ISequencerFeeVault.sol @@ -6,6 +6,10 @@ import { Types } from "src/libraries/Types.sol"; interface ISequencerFeeVault { error FeeVault_OnlyProxyAdminOwner(); + error InvalidInitialization(); + error NotInitializing(); + + event Initialized(uint64 version); event Withdrawal(uint256 value, address to, address from); event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount); @@ -16,6 +20,12 @@ interface ISequencerFeeVault { receive() external payable; + function initialize( + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + external; function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); @@ -30,11 +40,4 @@ interface ISequencerFeeVault { function version() external view returns (string memory); function l1FeeWallet() external view returns (address); - - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; } diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index af6d0b699ce..110f8c7f7c2 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -32,7 +32,7 @@ import { IGasPriceOracle } from "interfaces/L2/IGasPriceOracle.sol"; import { IL1Block } from "interfaces/L2/IL1Block.sol"; import { IFeeSplitter } from "interfaces/L2/IFeeSplitter.sol"; import { ISharesCalculator } from "interfaces/L2/ISharesCalculator.sol"; -import { IFeeVault, IFeeVaultConstructor } from "interfaces/L2/IFeeVault.sol"; +import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; import { IL1Withdrawer } from "interfaces/L2/IL1Withdrawer.sol"; import { ISuperchainRevSharesCalculator } from "interfaces/L2/ISuperchainRevSharesCalculator.sol"; @@ -320,24 +320,16 @@ contract L2Genesis is Script { network = Types.WithdrawalNetwork(_input.sequencerFeeVaultWithdrawalNetwork); } - ISequencerFeeVault vault = ISequencerFeeVault( - DeployUtils.create1({ - _name: "SequencerFeeVault", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IFeeVaultConstructor.__constructor__, - (recipient, _input.sequencerFeeVaultMinimumWithdrawalAmount, network) - ) - ) - }) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.SEQUENCER_FEE_WALLET); - vm.etch(impl, address(vault).code); + address impl = _setImplementationCode(Predeploys.SEQUENCER_FEE_WALLET); - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + /// Initialize the implemenation using max value for min withdrawal amount to make it unusable + ISequencerFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); + // Initialize the predeploy + ISequencerFeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).initialize({ + _recipient: recipient, + _minWithdrawalAmount: _input.sequencerFeeVaultMinimumWithdrawalAmount, + _withdrawalNetwork: network + }); } /// @notice This predeploy is following the safety invariant #1. @@ -418,24 +410,16 @@ contract L2Genesis is Script { network = Types.WithdrawalNetwork(_input.baseFeeVaultWithdrawalNetwork); } - IBaseFeeVault vault = IBaseFeeVault( - DeployUtils.create1({ - _name: "BaseFeeVault", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IFeeVaultConstructor.__constructor__, - (recipient, _input.baseFeeVaultMinimumWithdrawalAmount, network) - ) - ) - }) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.BASE_FEE_VAULT); - vm.etch(impl, address(vault).code); + address impl = _setImplementationCode(Predeploys.BASE_FEE_VAULT); - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + /// Initialize the implementation using max value for min withdrawal amount to make it unusable + IBaseFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); + // Initialize the predeploy + IBaseFeeVault(payable(Predeploys.BASE_FEE_VAULT)).initialize({ + _recipient: recipient, + _minWithdrawalAmount: _input.baseFeeVaultMinimumWithdrawalAmount, + _withdrawalNetwork: network + }); } /// @notice This predeploy is following the safety invariant #2. @@ -450,23 +434,16 @@ contract L2Genesis is Script { network = Types.WithdrawalNetwork(_input.l1FeeVaultWithdrawalNetwork); } - IL1FeeVault vault = IL1FeeVault( - DeployUtils.create1({ - _name: "L1FeeVault", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IFeeVaultConstructor.__constructor__, (recipient, _input.l1FeeVaultMinimumWithdrawalAmount, network) - ) - ) - }) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.L1_FEE_VAULT); - vm.etch(impl, address(vault).code); + address impl = _setImplementationCode(Predeploys.L1_FEE_VAULT); - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + /// Initialize the implementation using max value for min withdrawal amount to make it unusable + IL1FeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); + // Initialize the predeploy + IL1FeeVault(payable(Predeploys.L1_FEE_VAULT)).initialize({ + _recipient: recipient, + _minWithdrawalAmount: _input.l1FeeVaultMinimumWithdrawalAmount, + _withdrawalNetwork: network + }); } /// @notice This predeploy is following the safety invariant #2. @@ -481,24 +458,16 @@ contract L2Genesis is Script { network = Types.WithdrawalNetwork(_input.operatorFeeVaultWithdrawalNetwork); } - IOperatorFeeVault vault = IOperatorFeeVault( - DeployUtils.create1({ - _name: "OperatorFeeVault", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IFeeVaultConstructor.__constructor__, - (recipient, _input.operatorFeeVaultMinimumWithdrawalAmount, network) - ) - ) - }) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.OPERATOR_FEE_VAULT); - vm.etch(impl, address(vault).code); + address impl = _setImplementationCode(Predeploys.OPERATOR_FEE_VAULT); - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + /// Initialize the implementation using max value for min withdrawal amount to make it unusable + IOperatorFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); + // Initialize the predeploy + IOperatorFeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).initialize({ + _recipient: recipient, + _minWithdrawalAmount: _input.operatorFeeVaultMinimumWithdrawalAmount, + _withdrawalNetwork: network + }); } /// @notice This predeploy is following the safety invariant #2. diff --git a/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json b/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json index 8e16130ed75..63f770b275a 100644 --- a/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -63,6 +42,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minWithdrawalAmount", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_withdrawalNetwork", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "minWithdrawalAmount", @@ -180,6 +182,19 @@ "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -297,5 +312,15 @@ "inputs": [], "name": "FeeVault_OnlyProxyAdminOwner", "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/FeeVaultInitializer.json b/packages/contracts-bedrock/snapshots/abi/FeeVaultInitializer.json deleted file mode 100644 index 87b58357d78..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/FeeVaultInitializer.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "string", - "name": "vaultType", - "type": "string" - }, - { - "indexed": true, - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "enum Types.WithdrawalNetwork", - "name": "network", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "minWithdrawalAmount", - "type": "uint256" - } - ], - "name": "FeeVaultDeployed", - "type": "event" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json b/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json index 8e16130ed75..63f770b275a 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -63,6 +42,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minWithdrawalAmount", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_withdrawalNetwork", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "minWithdrawalAmount", @@ -180,6 +182,19 @@ "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -297,5 +312,15 @@ "inputs": [], "name": "FeeVault_OnlyProxyAdminOwner", "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json b/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json index 8e16130ed75..63f770b275a 100644 --- a/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -63,6 +42,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minWithdrawalAmount", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_withdrawalNetwork", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "minWithdrawalAmount", @@ -180,6 +182,19 @@ "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -297,5 +312,15 @@ "inputs": [], "name": "FeeVault_OnlyProxyAdminOwner", "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json b/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json index 333e253ab98..0b3563dcc71 100644 --- a/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -63,6 +42,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minWithdrawalAmount", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_withdrawalNetwork", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "l1FeeWallet", @@ -193,6 +195,19 @@ "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -310,5 +325,15 @@ "inputs": [], "name": "FeeVault_OnlyProxyAdminOwner", "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 6e4e13260ea..9025505a750 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -52,8 +52,8 @@ "sourceCodeHash": "0x006e3560f8b2e17133eb10a116916798ddc4345a7b006f8504dab69e810adb1c" }, "src/L2/BaseFeeVault.sol:BaseFeeVault": { - "initCodeHash": "0x6bfaa637e8f2e2b54f52efae2df015edaa99e61cff4ccd9e40c6488e262661bd", - "sourceCodeHash": "0x2e3673e0b592204ef30dc58d44c66d6587c8efe5fb5aeaf1a3a757343d06d09f" + "initCodeHash": "0x1793a3db107c6ee13e4d7925955aa9b96d4b2e068e1c8a8c54f99b2ab199449e", + "sourceCodeHash": "0xcb329746df0baddd3dc03c6c88da5d6bdc0f0a96d30e6dc78d0891bb1e935032" }, "src/L2/CrossL2Inbox.sol:CrossL2Inbox": { "initCodeHash": "0x56f868e561c4abe539043f98b16aad9305479e68fd03ece2233249b0c73a24ea", @@ -67,10 +67,6 @@ "initCodeHash": "0x6426953a0a4e92722d5dd264f6b23069353ed84ada2462a36104cd73392e6a8c", "sourceCodeHash": "0x09d876fcd1f7ea31627dae9a78b3c446d745ef67f0fb2b1feea6559e65875a58" }, - "src/L2/FeeVaultInitializer.sol:FeeVaultInitializer": { - "initCodeHash": "0x0a679fb899f24944ee6ffc42646df5ec9563799264ee2fecfcafb642f4e302c2", - "sourceCodeHash": "0x5169f19d03ec38d554edd06656e4ebc37cf37c56d0738e8a83cf95a837c72661" - }, "src/L2/GasPriceOracle.sol:GasPriceOracle": { "initCodeHash": "0x38ef70b2783dd45ad807afcf57972c7df4abaaeb5d16d17cdb451b9e931a9cbb", "sourceCodeHash": "0x4351fe2ac1106c8c220b8cfe7839bc107c24d8084deb21259ac954f5a362725d" @@ -80,8 +76,8 @@ "sourceCodeHash": "0x6e5349fd781d5f0127ff29ccea4d86a80240550cfa322364183a0f629abcb43e" }, "src/L2/L1FeeVault.sol:L1FeeVault": { - "initCodeHash": "0x6bfaa637e8f2e2b54f52efae2df015edaa99e61cff4ccd9e40c6488e262661bd", - "sourceCodeHash": "0x2e85139090b9072e368a5ff36e5fcf2a90b219c6024e06a7998904cd75412395" + "initCodeHash": "0x1793a3db107c6ee13e4d7925955aa9b96d4b2e068e1c8a8c54f99b2ab199449e", + "sourceCodeHash": "0x34186bcab29963237b4e0d7575b0a1cff7caf42ccdb55d4b2b2c767db3279189" }, "src/L2/L1Withdrawer.sol:L1Withdrawer": { "initCodeHash": "0x91e0be0d49636212678191c06b9b6840c399f08ad946bc7b52f24231691be28b", @@ -112,8 +108,8 @@ "sourceCodeHash": "0xbea4229c5c6988243dbc7cf5a086ddd412fe1f2903b8e20d56699fec8de0c2c9" }, "src/L2/OperatorFeeVault.sol:OperatorFeeVault": { - "initCodeHash": "0x6edc9100d267bac7009ae8bf9a3f5cbd5e4d61a395d93ea4d90adadd32211e07", - "sourceCodeHash": "0xcf6f8ca3a9d093c91722fe15489c6a5566f54dd38f14a82e7e063019e4ea507c" + "initCodeHash": "0x436d79247c0cb55b19e11db187ad4210c4b38434ba1d4025e7dc4bc581285be1", + "sourceCodeHash": "0xd6e94bc9df025855916aa4184d0bc739b0fbe786dfd037b99dbb51d0d3e46918" }, "src/L2/OptimismMintableERC721.sol:OptimismMintableERC721": { "initCodeHash": "0x316c6d716358f5b5284cd5457ea9fca4b5ad4a37835d4b4b300413dafbfa2159", @@ -136,8 +132,8 @@ "sourceCodeHash": "0x11b6236911e909ed10d4f194fe7315c1f5533d21cbe69a8ff16248c827df2647" }, "src/L2/SequencerFeeVault.sol:SequencerFeeVault": { - "initCodeHash": "0x4a0dd4ea6b3f9f16409d1a8dbd82f9b4e3ecd12c5264705b6d9539514a616cc6", - "sourceCodeHash": "0x755e5296877de76bb659212acae5980775825c7469c7a4d21f8f75bcdb5fbabd" + "initCodeHash": "0x3bfc3ba591ba099fbd83bb464cc261df94d705f7c8f46cfa358588d4eabbd858", + "sourceCodeHash": "0x5fa147acd34a5f1c451404234d22e114c79f1255decc51afd8930d5ce99d7e02" }, "src/L2/SuperchainERC20.sol:SuperchainERC20": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json index feacdd245f9..c72044ffabe 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json @@ -8,46 +8,25 @@ }, { "bytes": "32", - "label": "_minWithdrawalAmount", + "label": "minWithdrawalAmount", "offset": 0, "slot": "1", "type": "uint256" }, { "bytes": "20", - "label": "_recipient", + "label": "recipient", "offset": 0, "slot": "2", "type": "address" }, { "bytes": "1", - "label": "_withdrawalNetwork", + "label": "withdrawalNetwork", "offset": 20, "slot": "2", "type": "enum Types.WithdrawalNetwork" }, - { - "bytes": "1", - "label": "_ownerSetRecipient", - "offset": 21, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetMinWithdrawalAmount", - "offset": 22, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetWithdrawalNetwork", - "offset": 23, - "slot": "2", - "type": "bool" - }, { "bytes": "1472", "label": "__gap", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json b/packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1FeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/L1FeeVault.json index feacdd245f9..c72044ffabe 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1FeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1FeeVault.json @@ -8,46 +8,25 @@ }, { "bytes": "32", - "label": "_minWithdrawalAmount", + "label": "minWithdrawalAmount", "offset": 0, "slot": "1", "type": "uint256" }, { "bytes": "20", - "label": "_recipient", + "label": "recipient", "offset": 0, "slot": "2", "type": "address" }, { "bytes": "1", - "label": "_withdrawalNetwork", + "label": "withdrawalNetwork", "offset": 20, "slot": "2", "type": "enum Types.WithdrawalNetwork" }, - { - "bytes": "1", - "label": "_ownerSetRecipient", - "offset": 21, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetMinWithdrawalAmount", - "offset": 22, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetWithdrawalNetwork", - "offset": 23, - "slot": "2", - "type": "bool" - }, { "bytes": "1472", "label": "__gap", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json index feacdd245f9..c72044ffabe 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json @@ -8,46 +8,25 @@ }, { "bytes": "32", - "label": "_minWithdrawalAmount", + "label": "minWithdrawalAmount", "offset": 0, "slot": "1", "type": "uint256" }, { "bytes": "20", - "label": "_recipient", + "label": "recipient", "offset": 0, "slot": "2", "type": "address" }, { "bytes": "1", - "label": "_withdrawalNetwork", + "label": "withdrawalNetwork", "offset": 20, "slot": "2", "type": "enum Types.WithdrawalNetwork" }, - { - "bytes": "1", - "label": "_ownerSetRecipient", - "offset": 21, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetMinWithdrawalAmount", - "offset": 22, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetWithdrawalNetwork", - "offset": 23, - "slot": "2", - "type": "bool" - }, { "bytes": "1472", "label": "__gap", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json index feacdd245f9..c72044ffabe 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json @@ -8,46 +8,25 @@ }, { "bytes": "32", - "label": "_minWithdrawalAmount", + "label": "minWithdrawalAmount", "offset": 0, "slot": "1", "type": "uint256" }, { "bytes": "20", - "label": "_recipient", + "label": "recipient", "offset": 0, "slot": "2", "type": "address" }, { "bytes": "1", - "label": "_withdrawalNetwork", + "label": "withdrawalNetwork", "offset": 20, "slot": "2", "type": "enum Types.WithdrawalNetwork" }, - { - "bytes": "1", - "label": "_ownerSetRecipient", - "offset": 21, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetMinWithdrawalAmount", - "offset": 22, - "slot": "2", - "type": "bool" - }, - { - "bytes": "1", - "label": "_ownerSetWithdrawalNetwork", - "offset": 23, - "slot": "2", - "type": "bool" - }, { "bytes": "1472", "label": "__gap", diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index 21c171e5fd6..1f4e2024979 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -1,12 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Contracts import { FeeVault } from "src/L2/FeeVault.sol"; -// Libraries -import { Types } from "src/libraries/Types.sol"; - // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -18,16 +15,4 @@ contract BaseFeeVault is FeeVault, ISemver { /// @notice Semantic version. /// @custom:semver 1.6.0 string public constant version = "1.6.0"; - - /// @notice Constructs the BaseFeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } } diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index a546b72557e..0e2259123ff 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -1,65 +1,40 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Libraries import { SafeCall } from "src/libraries/SafeCall.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -// Libraries -import { Types } from "src/libraries/Types.sol"; +// External +// import from openzeppelin-contracts-v5 +import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; /// @title FeeVault /// @notice The FeeVault contract contains the basic logic for the various different vault contracts /// used to hold fee revenue generated by the L2 system. -abstract contract FeeVault { +abstract contract FeeVault is Initializable { /// @notice Error thrown when a function meant to be called by the ProxyAdmin owner is called by another account. error FeeVault_OnlyProxyAdminOwner(); - /// @notice Minimum balance before a withdrawal can be triggered. - /// Use the `minWithdrawalAmount()` getter as this is deprecated - /// and is subject to be removed in the future. - /// @custom:legacy - uint256 public immutable MIN_WITHDRAWAL_AMOUNT; - - /// @notice Account that will receive the fees. Can be located on L1 or L2. - /// Use the `recipient()` getter as this is deprecated - /// and is subject to be removed in the future. - /// @custom:legacy - address public immutable RECIPIENT; - - /// @notice Network which the recipient will receive fees on. - /// Use the `withdrawalNetwork()` getter as this is deprecated - /// and is subject to be removed in the future. - /// @custom:legacy - Types.WithdrawalNetwork public immutable WITHDRAWAL_NETWORK; - /// @notice The minimum gas limit for the FeeVault withdrawal transaction. - uint32 internal constant WITHDRAWAL_MIN_GAS = 400_000; + uint32 internal constant _WITHDRAWAL_MIN_GAS = 400_000; /// @notice Total amount of wei processed by the contract. uint256 public totalProcessed; /// @notice Minimum balance before a withdrawal can be triggered. - uint256 internal _minWithdrawalAmount; + uint256 public minWithdrawalAmount; /// @notice Account that will receive the fees. Can be located on L1 or L2. - address internal _recipient; + address public recipient; /// @notice Network which the recipient will receive fees on. - Types.WithdrawalNetwork internal _withdrawalNetwork; - - /// @notice Boolean flag tracking if the recipient has been set by the owner. - bool private _ownerSetRecipient; - - /// @notice Boolean flag tracking if the minimum withdrawal amount has been set by the owner. - bool private _ownerSetMinWithdrawalAmount; - - /// @notice Boolean flag tracking if the withdrawal network has been set by the owner. - bool private _ownerSetWithdrawalNetwork; + Types.WithdrawalNetwork public withdrawalNetwork; /// @notice Reserve extra slots in the storage layout for future upgrades, 50 in total. uint256[46] private __gap; @@ -95,14 +70,28 @@ abstract contract FeeVault { Types.WithdrawalNetwork oldWithdrawalNetwork, Types.WithdrawalNetwork newWithdrawalNetwork ); - /// @dev Using `__` on params to avoid warnings related to shadowing (even though there is no shadowing) - /// @param __recipient Wallet that will receive the fees. - /// @param __minWithdrawalAmount Minimum balance for withdrawals. - /// @param __withdrawalNetwork Network which the recipient will receive fees on. - constructor(address __recipient, uint256 __minWithdrawalAmount, Types.WithdrawalNetwork __withdrawalNetwork) { - RECIPIENT = __recipient; - MIN_WITHDRAWAL_AMOUNT = __minWithdrawalAmount; - WITHDRAWAL_NETWORK = __withdrawalNetwork; + /// @notice Constructor for the FeeVault contract. + /// This constructor is intentionally empty to prevent initialization. + /// Initialization is handled by the `initialize` function. + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the FeeVault contract. + /// @param _recipient Wallet that will receive the fees. + /// @param _minWithdrawalAmount Minimum balance for withdrawals. + /// @param _withdrawalNetwork Network which the recipient will receive fees on. + function initialize( + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + external + initializer + { + recipient = _recipient; + minWithdrawalAmount = _minWithdrawalAmount; + withdrawalNetwork = _withdrawalNetwork; } /// @notice Allow the contract to receive ETH. @@ -118,9 +107,8 @@ abstract contract FeeVault { revert FeeVault_OnlyProxyAdminOwner(); } - uint256 oldWithdrawalAmount = _minWithdrawalAmount; - _minWithdrawalAmount = _newMinWithdrawalAmount; - _ownerSetMinWithdrawalAmount = true; + uint256 oldWithdrawalAmount = minWithdrawalAmount; + minWithdrawalAmount = _newMinWithdrawalAmount; emit MinWithdrawalAmountUpdated(oldWithdrawalAmount, _newMinWithdrawalAmount); } @@ -132,9 +120,8 @@ abstract contract FeeVault { revert FeeVault_OnlyProxyAdminOwner(); } - address oldRecipient = _recipient; - _recipient = _newRecipient; - _ownerSetRecipient = true; + address oldRecipient = recipient; + recipient = _newRecipient; emit RecipientUpdated(oldRecipient, _newRecipient); } @@ -148,9 +135,8 @@ abstract contract FeeVault { revert FeeVault_OnlyProxyAdminOwner(); } - Types.WithdrawalNetwork oldWithdrawalNetwork = _withdrawalNetwork; - _withdrawalNetwork = _newWithdrawalNetwork; - _ownerSetWithdrawalNetwork = true; + Types.WithdrawalNetwork oldWithdrawalNetwork = withdrawalNetwork; + withdrawalNetwork = _newWithdrawalNetwork; emit WithdrawalNetworkUpdated(oldWithdrawalNetwork, _newWithdrawalNetwork); } @@ -159,58 +145,50 @@ abstract contract FeeVault { /// @return value_ The amount of ETH that was withdrawn. function withdraw() external returns (uint256 value_) { require( - address(this).balance >= minWithdrawalAmount(), + address(this).balance >= minWithdrawalAmount, "FeeVault: withdrawal amount must be greater than minimum withdrawal amount" ); value_ = address(this).balance; totalProcessed += value_; - emit Withdrawal(value_, recipient(), msg.sender); - emit Withdrawal(value_, recipient(), msg.sender, withdrawalNetwork()); + emit Withdrawal(value_, recipient, msg.sender); + emit Withdrawal(value_, recipient, msg.sender, withdrawalNetwork); - if (withdrawalNetwork() == Types.WithdrawalNetwork.L2) { - bool success = SafeCall.send(recipient(), value_); + if (withdrawalNetwork == Types.WithdrawalNetwork.L2) { + bool success = SafeCall.send(recipient, value_); require(success, "FeeVault: failed to send ETH to L2 fee recipient"); } else { IL2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal{ value: value_ }({ - _target: recipient(), - _gasLimit: WITHDRAWAL_MIN_GAS, + _target: recipient, + _gasLimit: _WITHDRAWAL_MIN_GAS, _data: hex"" }); } } - /// @notice Returns the minimum withdrawal amount for the vault. - /// @return The minimum withdrawal amount. - function minWithdrawalAmount() public view returns (uint256) { - if (_ownerSetMinWithdrawalAmount) { - // If the owner has set a value, use the storage variable - return _minWithdrawalAmount; - } - // If the owner has not set a value, use the immutable - return MIN_WITHDRAWAL_AMOUNT; + /// @notice Minimum balance before a withdrawal can be triggered. + /// Use the `minWithdrawalAmount()` getter as this is deprecated + /// and is subject to be removed in the future. + /// @custom:legacy + function MIN_WITHDRAWAL_AMOUNT() public view returns (uint256) { + return minWithdrawalAmount; } - /// @notice Returns the recipient of the fees. + /// @notice Account that will receive the fees. Can be located on L1 or L2. + /// Use the `recipient()` getter as this is deprecated + /// and is subject to be removed in the future. + /// @custom:legacy /// @return The recipient address. - function recipient() public view returns (address) { - if (_ownerSetRecipient) { - // If the owner has set a value, use the storage variable - return _recipient; - } - // If the owner has not set a value, use the immutable - return RECIPIENT; + function RECIPIENT() public view returns (address) { + return recipient; } - /// @notice Returns the withdrawal network for the vault. - /// @return The withdrawal network. - function withdrawalNetwork() public view returns (Types.WithdrawalNetwork) { - if (_ownerSetWithdrawalNetwork) { - // If the owner has set a value, use the storage variable - return _withdrawalNetwork; - } - // If the owner has not set a value, use the immutable - return WITHDRAWAL_NETWORK; + /// @notice Network which the recipient will receive fees on. + /// Use the `withdrawalNetwork()` getter as this is deprecated + /// and is subject to be removed in the future. + /// @custom:legacy + function WITHDRAWAL_NETWORK() public view returns (Types.WithdrawalNetwork) { + return withdrawalNetwork; } } diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol deleted file mode 100644 index 348edd1d202..00000000000 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Contracts -import { BaseFeeVault } from "src/L2/BaseFeeVault.sol"; -import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol"; -import { L1FeeVault } from "src/L2/L1FeeVault.sol"; -import { OperatorFeeVault } from "src/L2/OperatorFeeVault.sol"; - -// Libraries -import { Types } from "src/libraries/Types.sol"; -import { Predeploys } from "src/libraries/Predeploys.sol"; - -// Interfaces -import { ISemver } from "interfaces/universal/ISemver.sol"; -import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; - -/// @title FeeVaultInitializer -/// @notice This contract deploys new fee vault implementations with current configurations as immutables. -/// It reads the current configuration from existing fee vault proxies and deploys new implementations -/// with those values set as immutable parameters, ensuring consistent behavior across deployments. -contract FeeVaultInitializer is ISemver { - /// @notice Semantic version. - /// @custom:semver 1.0.0 - string public constant version = "1.0.0"; - - /// @notice Emitted when a fee vault implementation is deployed. - /// @param vaultType The type of fee vault being deployed. - /// @param newImplementation The deployed implementation address. - /// @param recipient The recipient address for the implementation. - /// @param network The withdrawal network for the implementation. - /// @param minWithdrawalAmount The minimum withdrawal amount for the implementation. - event FeeVaultDeployed( - string indexed vaultType, - address indexed newImplementation, - address recipient, - Types.WithdrawalNetwork network, - uint256 minWithdrawalAmount - ); - - /// @notice Constructor that deploys new fee vault implementations with current values as immutables. - constructor() { - _deployBaseFeeVault(); - _deploySequencerFeeVault(); - _deployL1FeeVault(); - _deployOperatorFeeVault(); - } - - /// @notice Helper function to get current fee vault configuration. - /// @param _feeVaultAddress The address of the fee vault to get configuration from. - /// @return recipient_ The recipient address. - /// @return network_ The withdrawal network. - /// @return minWithdrawalAmount_ The minimum withdrawal amount. - function _getFeeVaultConfig(address _feeVaultAddress) - internal - view - returns (address recipient_, Types.WithdrawalNetwork network_, uint256 minWithdrawalAmount_) - { - // Make sure to use legacy functions to avoid failure on upgrade. - recipient_ = IFeeVault(payable(_feeVaultAddress)).RECIPIENT(); - minWithdrawalAmount_ = IFeeVault(payable(_feeVaultAddress)).MIN_WITHDRAWAL_AMOUNT(); - // Use low level call to check for WITHDRAWAL_NETWORK, default to L2 if it doesn't exist - (bool success, bytes memory data) = - _feeVaultAddress.staticcall(abi.encodeCall(IFeeVault.WITHDRAWAL_NETWORK, ())); - network_ = - success && data.length >= 32 ? abi.decode(data, (Types.WithdrawalNetwork)) : Types.WithdrawalNetwork.L2; - } - - /// @notice Deploys a new Base Fee Vault implementation with current configuration as immutables. - /// Reads the current configuration from the existing proxy and deploys a new implementation - /// with those values set as immutable parameters. - function _deployBaseFeeVault() internal { - (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = - _getFeeVaultConfig(Predeploys.BASE_FEE_VAULT); - - // Deploy new implementation with current values as immutables - BaseFeeVault newBaseFeeVault = new BaseFeeVault(recipient, minWithdrawalAmount, network); - - emit FeeVaultDeployed("BaseFeeVault", address(newBaseFeeVault), recipient, network, minWithdrawalAmount); - } - - /// @notice Deploys a new Sequencer Fee Vault implementation with current configuration as immutables. - /// Reads the current configuration from the existing proxy and deploys a new implementation - /// with those values set as immutable parameters. - function _deploySequencerFeeVault() internal { - (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = - _getFeeVaultConfig(Predeploys.SEQUENCER_FEE_WALLET); - - // Deploy new implementation with current values as immutables - SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(recipient, minWithdrawalAmount, network); - - emit FeeVaultDeployed( - "SequencerFeeVault", address(newSequencerFeeVault), recipient, network, minWithdrawalAmount - ); - } - - /// @notice Deploys a new L1 Fee Vault implementation with current configuration as immutables. - /// Reads the current configuration from the existing proxy and deploys a new implementation - /// with those values set as immutable parameters. - function _deployL1FeeVault() internal { - (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = - _getFeeVaultConfig(Predeploys.L1_FEE_VAULT); - - // Deploy new implementation with current values as immutables - L1FeeVault newL1FeeVault = new L1FeeVault(recipient, minWithdrawalAmount, network); - - emit FeeVaultDeployed("L1FeeVault", address(newL1FeeVault), recipient, network, minWithdrawalAmount); - } - - /// @notice Deploys a new Operator Fee Vault implementation with current configuration as immutables. - /// Reads the current configuration from the existing proxy and deploys a new implementation - /// with those values set as immutable parameters. - function _deployOperatorFeeVault() internal { - (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = - _getFeeVaultConfig(Predeploys.OPERATOR_FEE_VAULT); - - // Deploy new implementation with current values as immutables - OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(recipient, minWithdrawalAmount, network); - - emit FeeVaultDeployed("OperatorFeeVault", address(newOperatorFeeVault), recipient, network, minWithdrawalAmount); - } -} diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index 58a37ea4e30..5e422d95dbb 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -1,12 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Contracts import { FeeVault } from "src/L2/FeeVault.sol"; -// Libraries -import { Types } from "src/libraries/Types.sol"; - // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -18,16 +15,4 @@ contract L1FeeVault is FeeVault, ISemver { /// @notice Semantic version. /// @custom:semver 1.6.0 string public constant version = "1.6.0"; - - /// @notice Constructs the L1FeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } } diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol index c888890d2ea..ca51c9ea403 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -1,12 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Contracts import { FeeVault } from "src/L2/FeeVault.sol"; -// Libraries -import { Types } from "src/libraries/Types.sol"; - // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -18,16 +15,4 @@ contract OperatorFeeVault is FeeVault, ISemver { /// @notice Semantic version. /// @custom:semver 1.1.0 string public constant version = "1.1.0"; - - /// @notice Constructs the OperatorFeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } } diff --git a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol index cef66410156..5c91b324270 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -1,12 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Contracts import { FeeVault } from "src/L2/FeeVault.sol"; -// Libraries -import { Types } from "src/libraries/Types.sol"; - // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -19,22 +16,10 @@ contract SequencerFeeVault is FeeVault, ISemver { /// @custom:semver 1.6.0 string public constant version = "1.6.0"; - /// @notice Constructs the SequencerFeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } - /// @custom:legacy /// @notice Legacy getter for the recipient address. /// @return The recipient address. function l1FeeWallet() public view returns (address) { - return recipient(); + return recipient; } } diff --git a/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol b/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol index 0c470f2bdab..8cc6bc0da46 100644 --- a/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol @@ -7,6 +7,7 @@ import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; import { FeeVault_Uncategorized_Test } from "test/L2/FeeVault.t.sol"; +import { Types } from "src/libraries/Types.sol"; /// @title BaseFeeVault_Uncategorized_Test /// @notice Test contract for the BaseFeeVault contract's functionality @@ -18,6 +19,7 @@ contract BaseFeeVault_Uncategorized_Test is FeeVault_Uncategorized_Test { feeVaultName = "BaseFeeVault"; minWithdrawalAmount = deploy.cfg().baseFeeVaultMinimumWithdrawalAmount(); feeVault = IFeeVault(payable(Predeploys.BASE_FEE_VAULT)); + withdrawalNetwork = Types.WithdrawalNetwork(uint8(deploy.cfg().baseFeeVaultWithdrawalNetwork())); // Current recipient is a contract that reverts when receiving fees, so etching empty bytes to it vm.etch(recipient, hex""); } diff --git a/packages/contracts-bedrock/test/L2/FeeVault.t.sol b/packages/contracts-bedrock/test/L2/FeeVault.t.sol index 98c69708943..03ae05ec6b5 100644 --- a/packages/contracts-bedrock/test/L2/FeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeVault.t.sol @@ -4,17 +4,16 @@ pragma solidity 0.8.15; // Testing import { CommonTest } from "test/setup/CommonTest.sol"; import { Reverter } from "test/mocks/Callers.sol"; -import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; // Interfaces import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -import { IFeeVault, IFeeVaultConstructor } from "interfaces/L2/IFeeVault.sol"; +import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; +import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; import { Types } from "src/libraries/Types.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; -import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; /// @title FeeVault_Uncategorized_Test /// @notice Abstract test contract for fee feeVault testing. @@ -25,42 +24,35 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { IFeeVault feeVault; string feeVaultName; uint256 minWithdrawalAmount; - Types.WithdrawalNetwork expectedWithdrawalNetwork; - - /// @dev Sets up the test suite. - function setUp() public virtual override { - // Default to L1 - expectedWithdrawalNetwork = Types.WithdrawalNetwork.L1; - super.setUp(); - } + Types.WithdrawalNetwork withdrawalNetwork; /// @notice Helper function to set up L2 withdrawal configuration. function _setupL2Withdrawal() internal { - // Alter the deployment to use WithdrawalNetwork.L2 - vm.etch( - EIP1967Helper.getImplementation(address(feeVault)), - address( - DeployUtils.create1({ - _name: feeVaultName, - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IFeeVaultConstructor.__constructor__, - (recipient, minWithdrawalAmount, Types.WithdrawalNetwork.L2) - ) - ) - }) - ).code - ); + // Set the withdrawal network to L2 + vm.prank(IProxyAdmin(Predeploys.PROXY_ADMIN).owner()); + feeVault.setWithdrawalNetwork(Types.WithdrawalNetwork.L2); } /// @notice Tests that the l1 fee wallet is correct. function test_constructor_succeeds() external view { assertEq(feeVault.RECIPIENT(), recipient); - assertEq(feeVault.recipient(), recipient); assertEq(feeVault.MIN_WITHDRAWAL_AMOUNT(), minWithdrawalAmount); + assertEq(uint8(feeVault.WITHDRAWAL_NETWORK()), uint8(withdrawalNetwork)); + } + + /// @notice Tests that the initialize function succeeds. + function test_initialize_succeeds() external view { + assertEq(feeVault.recipient(), recipient); assertEq(feeVault.minWithdrawalAmount(), minWithdrawalAmount); - assertEq(uint8(feeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L1)); - assertEq(uint8(feeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L1)); + assertEq(uint8(feeVault.withdrawalNetwork()), uint8(withdrawalNetwork)); + } + + /// @notice Tests that the initialize function reverts if the contract is already initialized. + function test_initialize_reinitialization_reverts() external { + _setupL2Withdrawal(); + + vm.expectRevert(IFeeVault.InvalidInitialization.selector); + feeVault.initialize(recipient, minWithdrawalAmount, Types.WithdrawalNetwork.L1); } /// @notice Tests that the fee feeVault is able to receive ETH. @@ -76,8 +68,14 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { /// @notice Tests that `withdraw` reverts if the balance is less than the minimum withdrawal /// amount. - function test_withdraw_notEnough_reverts() external { - assert(address(feeVault).balance < feeVault.MIN_WITHDRAWAL_AMOUNT()); + function test_withdraw_notEnough_reverts(uint256 _minWithdrawalAmount) external { + // Set the minimum withdrawal amount + _minWithdrawalAmount = bound(_minWithdrawalAmount, 1, type(uint256).max); + vm.prank(IProxyAdmin(Predeploys.PROXY_ADMIN).owner()); + feeVault.setMinWithdrawalAmount(_minWithdrawalAmount); + + // Set the balance to be less than the minimum withdrawal amount + vm.deal(address(feeVault), _minWithdrawalAmount - 1); vm.expectRevert("FeeVault: withdrawal amount must be greater than minimum withdrawal amount"); feeVault.withdraw(); @@ -85,7 +83,20 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { /// @notice Tests that `withdraw` successfully initiates a withdrawal to L1. function test_withdraw_toL1_succeeds() external { - uint256 amount = feeVault.MIN_WITHDRAWAL_AMOUNT() + 1; + // Setup L1 withdrawal + vm.prank(IProxyAdmin(Predeploys.PROXY_ADMIN).owner()); + feeVault.setWithdrawalNetwork(Types.WithdrawalNetwork.L1); + + // Set recipient + vm.prank(IProxyAdmin(Predeploys.PROXY_ADMIN).owner()); + feeVault.setRecipient(recipient); + + // Set minimum withdrawal amount + vm.prank(IProxyAdmin(Predeploys.PROXY_ADMIN).owner()); + feeVault.setMinWithdrawalAmount(minWithdrawalAmount); + + // Set the balance to be greater than the minimum withdrawal amount + uint256 amount = feeVault.minWithdrawalAmount() + 1; vm.deal(address(feeVault), amount); // No ether has been withdrawn yet @@ -97,7 +108,11 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { emit Withdrawal(address(feeVault).balance, recipient, address(this), Types.WithdrawalNetwork.L1); // The entire feeVault's balance is withdrawn - vm.expectCall(Predeploys.L2_TO_L1_MESSAGE_PASSER, address(feeVault).balance, hex""); + vm.expectCall( + Predeploys.L2_TO_L1_MESSAGE_PASSER, + address(feeVault).balance, + abi.encodeCall(IL2ToL1MessagePasser.initiateWithdrawal, (recipient, 400_000, hex"")) + ); // The message is passed to the correct recipient vm.expectEmit(Predeploys.L2_TO_L1_MESSAGE_PASSER); @@ -132,7 +147,7 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { function test_withdraw_toL2_succeeds() public { _setupL2Withdrawal(); - uint256 amount = feeVault.MIN_WITHDRAWAL_AMOUNT() + 1; + uint256 amount = feeVault.minWithdrawalAmount() + 1; vm.deal(address(feeVault), amount); // No ether has been withdrawn yet @@ -160,7 +175,7 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { function test_withdraw_toL2recipientReverts_fails() external { _setupL2Withdrawal(); - uint256 amount = feeVault.MIN_WITHDRAWAL_AMOUNT(); + uint256 amount = feeVault.minWithdrawalAmount(); vm.deal(address(feeVault), amount); // No ether has been withdrawn yet @@ -177,14 +192,14 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { } /// @notice Tests that the owner can successfully set minimum withdrawal amount with fuzz testing. - function testFuzz_setMinWithdrawalAmount_succeeds(uint256 _newAmount) external { + function testFuzz_setMinWithdrawalAmount_succeeds(uint256 _newMinWithdrawalAmount) external { address owner = IProxyAdmin(Predeploys.PROXY_ADMIN).owner(); vm.prank(owner); - IFeeVault(payable(address(feeVault))).setMinWithdrawalAmount(_newAmount); + IFeeVault(payable(address(feeVault))).setMinWithdrawalAmount(_newMinWithdrawalAmount); // Verify the value was updated - assertEq(feeVault.minWithdrawalAmount(), _newAmount); + assertEq(feeVault.minWithdrawalAmount(), _newMinWithdrawalAmount); } /// @notice Tests that non-owner cannot set minimum withdrawal amount with fuzz testing. @@ -261,62 +276,4 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { // Verify the value and boolean flag were NOT changed assertEq(uint8(feeVault.withdrawalNetwork()), uint8(initialNetwork)); } - - /// @notice Tests that minWithdrawalAmount returns immutable by default, then storage after being set. - function test_minWithdrawalAmount_returnsImmutableThenStorage_succeeds() external { - address owner = IProxyAdmin(Predeploys.PROXY_ADMIN).owner(); - - // Initially should return the immutable value - uint256 immutableValue = feeVault.MIN_WITHDRAWAL_AMOUNT(); - assertEq(feeVault.minWithdrawalAmount(), immutableValue); - - // Set a different value via owner - uint256 newValue = immutableValue + 1 ether; - vm.prank(owner); - IFeeVault(payable(address(feeVault))).setMinWithdrawalAmount(newValue); - - // Now should return the storage value, not the immutable - assertEq(feeVault.minWithdrawalAmount(), newValue); - assertNotEq(feeVault.minWithdrawalAmount(), immutableValue); - assertEq(feeVault.MIN_WITHDRAWAL_AMOUNT(), immutableValue); // immutable unchanged - } - - /// @notice Tests that recipient returns immutable by default, then storage after being set. - function test_recipient_returnsImmutableThenStorage_succeeds() external { - address owner = IProxyAdmin(Predeploys.PROXY_ADMIN).owner(); - - // Initially should return the immutable value - address immutableValue = feeVault.RECIPIENT(); - assertEq(feeVault.recipient(), immutableValue); - - // Set a different value via owner - address newValue = address(0x123); - vm.prank(owner); - IFeeVault(payable(address(feeVault))).setRecipient(newValue); - - // Now should return the storage value, not the immutable - assertEq(feeVault.recipient(), newValue); - assertNotEq(feeVault.recipient(), immutableValue); - assertEq(feeVault.RECIPIENT(), immutableValue); // immutable unchanged - } - - /// @notice Tests that withdrawalNetwork returns immutable by default, then storage after being set. - function test_withdrawalNetwork_returnsImmutableThenStorage_succeeds() external { - address owner = IProxyAdmin(Predeploys.PROXY_ADMIN).owner(); - - // Initially should return the immutable value - Types.WithdrawalNetwork immutableValue = feeVault.WITHDRAWAL_NETWORK(); - assertEq(uint8(feeVault.withdrawalNetwork()), uint8(immutableValue)); - - // Set a different value via owner (toggle between L1 and L2) - Types.WithdrawalNetwork newValue = - immutableValue == Types.WithdrawalNetwork.L1 ? Types.WithdrawalNetwork.L2 : Types.WithdrawalNetwork.L1; - vm.prank(owner); - IFeeVault(payable(address(feeVault))).setWithdrawalNetwork(newValue); - - // Now should return the storage value, not the immutable - assertEq(uint8(feeVault.withdrawalNetwork()), uint8(newValue)); - assertNotEq(uint8(feeVault.withdrawalNetwork()), uint8(immutableValue)); - assertEq(uint8(feeVault.WITHDRAWAL_NETWORK()), uint8(immutableValue)); // immutable unchanged - } } diff --git a/packages/contracts-bedrock/test/L2/FeeVaultInitializer.t.sol b/packages/contracts-bedrock/test/L2/FeeVaultInitializer.t.sol deleted file mode 100644 index d0a8db0038c..00000000000 --- a/packages/contracts-bedrock/test/L2/FeeVaultInitializer.t.sol +++ /dev/null @@ -1,400 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Testing -import { CommonTest } from "test/setup/CommonTest.sol"; - -// Contracts -import { FeeVaultInitializer } from "src/L2/FeeVaultInitializer.sol"; - -// Mocks -import { MockLegacyFeeVault } from "test/mocks/MockFeeVault.sol"; - -// Libraries -import { Types } from "src/libraries/Types.sol"; - -// Interfaces -import { IBaseFeeVault } from "interfaces/L2/IBaseFeeVault.sol"; -import { ISequencerFeeVault } from "interfaces/L2/ISequencerFeeVault.sol"; -import { IL1FeeVault } from "interfaces/L2/IL1FeeVault.sol"; -import { IOperatorFeeVault } from "interfaces/L2/IOperatorFeeVault.sol"; - -// Libraries -import { Predeploys } from "src/libraries/Predeploys.sol"; -import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; - -/// @title FeeVaultInitializer_Constructor_Test -/// @notice Test contract for the FeeVaultInitializer contract's functionality -contract FeeVaultInitializer_Constructor_Test is CommonTest { - FeeVaultInitializer feeVaultInitializer; - - // Store original vault configurations - address originalBaseRecipient; - uint256 originalBaseMinWithdrawal; - Types.WithdrawalNetwork originalBaseNetwork; - - address originalSequencerRecipient; - uint256 originalSequencerMinWithdrawal; - Types.WithdrawalNetwork originalSequencerNetwork; - - address originalL1Recipient; - uint256 originalL1MinWithdrawal; - Types.WithdrawalNetwork originalL1Network; - - address originalOperatorRecipient; - uint256 originalOperatorMinWithdrawal; - Types.WithdrawalNetwork originalOperatorNetwork; - - event FeeVaultDeployed( - string indexed vaultType, - address indexed newImplementation, - address recipient, - Types.WithdrawalNetwork network, - uint256 minWithdrawalAmount - ); - - function _mockAndExpect(address _receiver, bytes memory _calldata, bytes memory _returned) internal { - vm.mockCall(_receiver, _calldata, _returned); - vm.expectCall(_receiver, _calldata); - } - - function setUp() public override { - super.setUp(); - - // Capture original Base Fee Vault configuration - originalBaseRecipient = baseFeeVault.RECIPIENT(); - originalBaseMinWithdrawal = baseFeeVault.MIN_WITHDRAWAL_AMOUNT(); - originalBaseNetwork = baseFeeVault.WITHDRAWAL_NETWORK(); - - // Capture original Sequencer Fee Vault configuration - originalSequencerRecipient = sequencerFeeVault.RECIPIENT(); - originalSequencerMinWithdrawal = sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(); - originalSequencerNetwork = sequencerFeeVault.WITHDRAWAL_NETWORK(); - - // Capture original L1 Fee Vault configuration - originalL1Recipient = l1FeeVault.RECIPIENT(); - originalL1MinWithdrawal = l1FeeVault.MIN_WITHDRAWAL_AMOUNT(); - originalL1Network = l1FeeVault.WITHDRAWAL_NETWORK(); - - // Capture original Operator Fee Vault configuration - originalOperatorRecipient = operatorFeeVault.RECIPIENT(); - originalOperatorMinWithdrawal = operatorFeeVault.MIN_WITHDRAWAL_AMOUNT(); - originalOperatorNetwork = operatorFeeVault.WITHDRAWAL_NETWORK(); - } - - function test_constructor_succeeds() public { - // Get the current nonce and predicted initializer address to predict the vault addresses - uint64 currentNonce = vm.getNonce(address(this)); - address predictedInitializerAddress = vm.computeCreateAddress(address(this), currentNonce); - - // Test event emissions before fee vault initializer deployment - _testEventEmissions(predictedInitializerAddress); - - // Deploy the FeeVaultInitializer - feeVaultInitializer = new FeeVaultInitializer(); - - // Can now read the fee vault initializer version - assertEq(feeVaultInitializer.version(), "1.0.0"); - assertEq(address(feeVaultInitializer), predictedInitializerAddress); - - // Test the new implementations have correct configurations against the original values - _testNewImplementations(predictedInitializerAddress); - } - - function test_constructor_withLegacyBaseFeeVault_succeeds() public { - // Deploy the legacy mock vault - MockLegacyFeeVault legacyVault = new MockLegacyFeeVault(); - - // Use vm.etch to replace the base fee vault predeploy with our legacy mock - // This simulates an old vault that doesn't have the WITHDRAWAL_NETWORK function - vm.etch(Predeploys.BASE_FEE_VAULT, address(legacyVault).code); - - // Get the current nonce and predicted initializer address - uint64 currentNonce = vm.getNonce(address(this)); - address predictedInitializerAddress = vm.computeCreateAddress(address(this), currentNonce); - address predictedBaseFeeVault = vm.computeCreateAddress(predictedInitializerAddress, 1); - - // Expect the FeeVaultDeployed event with default L2 network for the legacy vault - vm.expectEmit(predictedInitializerAddress); - emit FeeVaultDeployed( - "BaseFeeVault", - predictedBaseFeeVault, - legacyVault.RECIPIENT(), - Types.WithdrawalNetwork.L2, // Should default to L2 - legacyVault.MIN_WITHDRAWAL_AMOUNT() - ); - - // Deploy the FeeVaultInitializer - this should handle the legacy vault gracefully - feeVaultInitializer = new FeeVaultInitializer(); - - // Verify the implementation was deployed correctly with default L2 network - IBaseFeeVault newBaseFeeVault = IBaseFeeVault(payable(predictedBaseFeeVault)); - assertEq(newBaseFeeVault.RECIPIENT(), legacyVault.RECIPIENT()); - assertEq(newBaseFeeVault.MIN_WITHDRAWAL_AMOUNT(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newBaseFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); - - // Check new getter functions also return the correct values - assertEq(newBaseFeeVault.recipient(), legacyVault.RECIPIENT()); - assertEq(newBaseFeeVault.minWithdrawalAmount(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newBaseFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); - } - - function test_constructor_whenVaultsWithdrawalNetworkIsL2_succeeds() public { - // Mock the calls to the fee vaults to return L2 as the withdrawal network - _mockAndExpect( - Predeploys.BASE_FEE_VAULT, - abi.encodeCall(IBaseFeeVault.WITHDRAWAL_NETWORK, ()), - abi.encode(Types.WithdrawalNetwork.L2) - ); - _mockAndExpect( - Predeploys.SEQUENCER_FEE_WALLET, - abi.encodeCall(ISequencerFeeVault.WITHDRAWAL_NETWORK, ()), - abi.encode(Types.WithdrawalNetwork.L2) - ); - _mockAndExpect( - Predeploys.L1_FEE_VAULT, - abi.encodeCall(IL1FeeVault.WITHDRAWAL_NETWORK, ()), - abi.encode(Types.WithdrawalNetwork.L2) - ); - _mockAndExpect( - Predeploys.OPERATOR_FEE_VAULT, - abi.encodeCall(IOperatorFeeVault.WITHDRAWAL_NETWORK, ()), - abi.encode(Types.WithdrawalNetwork.L2) - ); - - address predictedInitializerAddress = vm.computeCreateAddress(address(this), vm.getNonce(address(this))); - address predictedBaseFeeVault = vm.computeCreateAddress(predictedInitializerAddress, 1); - address predictedSequencerFeeVault = vm.computeCreateAddress(predictedInitializerAddress, 2); - address predictedL1FeeVault = vm.computeCreateAddress(predictedInitializerAddress, 3); - address predictedOperatorFeeVault = vm.computeCreateAddress(predictedInitializerAddress, 4); - - // Deploy the FeeVaultInitializer - feeVaultInitializer = new FeeVaultInitializer(); - - // Check the vault's withdrawal network is L2 - assertEq( - uint8(IFeeVault(payable(predictedBaseFeeVault)).withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2) - ); - assertEq( - uint8(IFeeVault(payable(predictedSequencerFeeVault)).withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2) - ); - assertEq(uint8(IFeeVault(payable(predictedL1FeeVault)).withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); - assertEq( - uint8(IFeeVault(payable(predictedOperatorFeeVault)).withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2) - ); - } - - function test_constructor_withLegacySequencerFeeVault_succeeds() public { - // Deploy the legacy mock vault - MockLegacyFeeVault legacyVault = new MockLegacyFeeVault(); - - // Use vm.etch to replace the sequencer fee wallet predeploy with our legacy mock - // This simulates an old vault that doesn't have the WITHDRAWAL_NETWORK function - vm.etch(Predeploys.SEQUENCER_FEE_WALLET, address(legacyVault).code); - - // Get the current nonce and predicted initializer address - uint64 currentNonce = vm.getNonce(address(this)); - address predictedInitializerAddress = vm.computeCreateAddress(address(this), currentNonce); - address predictedSequencerFeeVault = vm.computeCreateAddress(predictedInitializerAddress, 2); - - // Expect the FeeVaultDeployed event with default L2 network for the legacy vault - vm.expectEmit(predictedInitializerAddress); - emit FeeVaultDeployed( - "SequencerFeeVault", - predictedSequencerFeeVault, - legacyVault.RECIPIENT(), - Types.WithdrawalNetwork.L2, // Should default to L2 - legacyVault.MIN_WITHDRAWAL_AMOUNT() - ); - - // Deploy the FeeVaultInitializer - this should handle the legacy vault gracefully - feeVaultInitializer = new FeeVaultInitializer(); - - // Verify the implementation was deployed correctly with default L2 network - ISequencerFeeVault newSequencerFeeVault = ISequencerFeeVault(payable(predictedSequencerFeeVault)); - assertEq(newSequencerFeeVault.RECIPIENT(), legacyVault.RECIPIENT()); - assertEq(newSequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newSequencerFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); - - // Check new getter functions also return the correct values - assertEq(newSequencerFeeVault.recipient(), legacyVault.RECIPIENT()); - assertEq(newSequencerFeeVault.minWithdrawalAmount(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newSequencerFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); - } - - function test_constructor_withLegacyL1FeeVault_succeeds() public { - // Deploy the legacy mock vault - MockLegacyFeeVault legacyVault = new MockLegacyFeeVault(); - - // Use vm.etch to replace the l1 fee vault predeploy with our legacy mock - // This simulates an old vault that doesn't have the WITHDRAWAL_NETWORK function - vm.etch(Predeploys.L1_FEE_VAULT, address(legacyVault).code); - - // Get the current nonce and predicted initializer address - uint64 currentNonce = vm.getNonce(address(this)); - address predictedInitializerAddress = vm.computeCreateAddress(address(this), currentNonce); - address predictedL1FeeVault = vm.computeCreateAddress(predictedInitializerAddress, 3); - - // Expect the FeeVaultDeployed event with default L2 network for the legacy vault - vm.expectEmit(predictedInitializerAddress); - emit FeeVaultDeployed( - "L1FeeVault", - predictedL1FeeVault, - legacyVault.RECIPIENT(), - Types.WithdrawalNetwork.L2, // Should default to L2 - legacyVault.MIN_WITHDRAWAL_AMOUNT() - ); - - // Deploy the FeeVaultInitializer - this should handle the legacy vault gracefully - feeVaultInitializer = new FeeVaultInitializer(); - - // Verify the implementation was deployed correctly with default L2 network - IL1FeeVault newL1FeeVault = IL1FeeVault(payable(predictedL1FeeVault)); - assertEq(newL1FeeVault.RECIPIENT(), legacyVault.RECIPIENT()); - assertEq(newL1FeeVault.MIN_WITHDRAWAL_AMOUNT(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newL1FeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); - - // Check new getter functions also return the correct values - assertEq(newL1FeeVault.recipient(), legacyVault.RECIPIENT()); - assertEq(newL1FeeVault.minWithdrawalAmount(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newL1FeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); - } - - function test_constructor_withLegacyOperatorFeeVault_succeeds() public { - // Deploy the legacy mock vault - MockLegacyFeeVault legacyVault = new MockLegacyFeeVault(); - - // Use vm.etch to replace the operator fee vault predeploy with our legacy mock - // This simulates an old vault that doesn't have the WITHDRAWAL_NETWORK function - vm.etch(Predeploys.OPERATOR_FEE_VAULT, address(legacyVault).code); - - // Get the current nonce and predicted initializer address - uint64 currentNonce = vm.getNonce(address(this)); - address predictedInitializerAddress = vm.computeCreateAddress(address(this), currentNonce); - address predictedOperatorFeeVault = vm.computeCreateAddress(predictedInitializerAddress, 4); - - // Expect the FeeVaultDeployed event with default L2 network for the legacy vault - vm.expectEmit(predictedInitializerAddress); - emit FeeVaultDeployed( - "OperatorFeeVault", - predictedOperatorFeeVault, - legacyVault.RECIPIENT(), - Types.WithdrawalNetwork.L2, // Should default to L2 - legacyVault.MIN_WITHDRAWAL_AMOUNT() - ); - - // Deploy the FeeVaultInitializer - this should handle the legacy vault gracefully - feeVaultInitializer = new FeeVaultInitializer(); - - // Verify the implementation was deployed correctly with default L2 network - IOperatorFeeVault newOperatorFeeVault = IOperatorFeeVault(payable(predictedOperatorFeeVault)); - assertEq(newOperatorFeeVault.RECIPIENT(), legacyVault.RECIPIENT()); - assertEq(newOperatorFeeVault.MIN_WITHDRAWAL_AMOUNT(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newOperatorFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); - - // Check new getter functions also return the correct values - assertEq(newOperatorFeeVault.recipient(), legacyVault.RECIPIENT()); - assertEq(newOperatorFeeVault.minWithdrawalAmount(), legacyVault.MIN_WITHDRAWAL_AMOUNT()); - assertEq(uint8(newOperatorFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); - } - - function _testEventEmissions(address _predictedInitializerAddress) internal { - address predictedBaseFeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 1); - address predictedSequencerFeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 2); - address predictedL1FeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 3); - address predictedOperatorFeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 4); - - // Expect the FeeVaultDeployed events from the FeeVaultInitializer contract using the original values - vm.expectEmit(_predictedInitializerAddress); - emit FeeVaultDeployed( - "BaseFeeVault", predictedBaseFeeVault, originalBaseRecipient, originalBaseNetwork, originalBaseMinWithdrawal - ); - - vm.expectEmit(_predictedInitializerAddress); - emit FeeVaultDeployed( - "SequencerFeeVault", - predictedSequencerFeeVault, - originalSequencerRecipient, - originalSequencerNetwork, - originalSequencerMinWithdrawal - ); - - vm.expectEmit(_predictedInitializerAddress); - emit FeeVaultDeployed( - "L1FeeVault", predictedL1FeeVault, originalL1Recipient, originalL1Network, originalL1MinWithdrawal - ); - - vm.expectEmit(_predictedInitializerAddress); - emit FeeVaultDeployed( - "OperatorFeeVault", - predictedOperatorFeeVault, - originalOperatorRecipient, - originalOperatorNetwork, - originalOperatorMinWithdrawal - ); - } - - function _testNewImplementations(address _predictedInitializerAddress) internal view { - address predictedBaseFeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 1); - address predictedSequencerFeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 2); - address predictedL1FeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 3); - address predictedOperatorFeeVault = vm.computeCreateAddress(_predictedInitializerAddress, 4); - - _testBaseFeeVaultImplementation(predictedBaseFeeVault); - _testSequencerFeeVaultImplementation(predictedSequencerFeeVault); - _testL1FeeVaultImplementation(predictedL1FeeVault); - _testOperatorFeeVaultImplementation(predictedOperatorFeeVault); - } - - function _testBaseFeeVaultImplementation(address _newImplementation) internal view { - IBaseFeeVault newBaseFeeVault = IBaseFeeVault(payable(_newImplementation)); - // Test against the original stored values - assertEq(newBaseFeeVault.RECIPIENT(), originalBaseRecipient); - assertEq(newBaseFeeVault.MIN_WITHDRAWAL_AMOUNT(), originalBaseMinWithdrawal); - assertEq(uint8(newBaseFeeVault.WITHDRAWAL_NETWORK()), uint8(originalBaseNetwork)); - - // Check new getter functions return the same original values - assertEq(newBaseFeeVault.recipient(), originalBaseRecipient); - assertEq(newBaseFeeVault.minWithdrawalAmount(), originalBaseMinWithdrawal); - assertEq(uint8(newBaseFeeVault.withdrawalNetwork()), uint8(originalBaseNetwork)); - } - - function _testSequencerFeeVaultImplementation(address _newImplementation) internal view { - ISequencerFeeVault newSequencerFeeVault = ISequencerFeeVault(payable(_newImplementation)); - // Test against the original stored values - assertEq(newSequencerFeeVault.RECIPIENT(), originalSequencerRecipient); - assertEq(newSequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), originalSequencerMinWithdrawal); - assertEq(uint8(newSequencerFeeVault.WITHDRAWAL_NETWORK()), uint8(originalSequencerNetwork)); - - // Check new getter functions return the same original values - assertEq(newSequencerFeeVault.recipient(), originalSequencerRecipient); - assertEq(newSequencerFeeVault.minWithdrawalAmount(), originalSequencerMinWithdrawal); - assertEq(uint8(newSequencerFeeVault.withdrawalNetwork()), uint8(originalSequencerNetwork)); - } - - function _testL1FeeVaultImplementation(address _newImplementation) internal view { - IL1FeeVault newL1FeeVault = IL1FeeVault(payable(_newImplementation)); - // Test against the original stored values - assertEq(newL1FeeVault.RECIPIENT(), originalL1Recipient); - assertEq(newL1FeeVault.MIN_WITHDRAWAL_AMOUNT(), originalL1MinWithdrawal); - assertEq(uint8(newL1FeeVault.WITHDRAWAL_NETWORK()), uint8(originalL1Network)); - - // Check new getter functions return the same original values - assertEq(newL1FeeVault.recipient(), originalL1Recipient); - assertEq(newL1FeeVault.minWithdrawalAmount(), originalL1MinWithdrawal); - assertEq(uint8(newL1FeeVault.withdrawalNetwork()), uint8(originalL1Network)); - } - - function _testOperatorFeeVaultImplementation(address _newImplementation) internal view { - IOperatorFeeVault newOperatorFeeVault = IOperatorFeeVault(payable(_newImplementation)); - // Test against the original stored values - assertEq(newOperatorFeeVault.RECIPIENT(), originalOperatorRecipient); - assertEq(newOperatorFeeVault.MIN_WITHDRAWAL_AMOUNT(), originalOperatorMinWithdrawal); - assertEq(uint8(newOperatorFeeVault.WITHDRAWAL_NETWORK()), uint8(originalOperatorNetwork)); - - // Check new getter functions return the same original values - assertEq(newOperatorFeeVault.recipient(), originalOperatorRecipient); - assertEq(newOperatorFeeVault.minWithdrawalAmount(), originalOperatorMinWithdrawal); - assertEq(uint8(newOperatorFeeVault.withdrawalNetwork()), uint8(originalOperatorNetwork)); - } -} diff --git a/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol b/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol index dc18b8f33d3..b67c8798892 100644 --- a/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol @@ -7,6 +7,7 @@ import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; import { FeeVault_Uncategorized_Test } from "test/L2/FeeVault.t.sol"; +import { Types } from "src/libraries/Types.sol"; /// @title L1FeeVault_Uncategorized_Test /// @notice Test contract for the L1FeeVault contract's functionality @@ -18,5 +19,6 @@ contract L1FeeVault_Uncategorized_Test is FeeVault_Uncategorized_Test { feeVaultName = "L1FeeVault"; minWithdrawalAmount = deploy.cfg().l1FeeVaultMinimumWithdrawalAmount(); feeVault = IFeeVault(payable(Predeploys.L1_FEE_VAULT)); + withdrawalNetwork = Types.WithdrawalNetwork(uint8(deploy.cfg().l1FeeVaultWithdrawalNetwork())); } } diff --git a/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol b/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol index e09476bfbe1..e5d5b26a2f5 100644 --- a/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol @@ -7,6 +7,7 @@ import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; import { FeeVault_Uncategorized_Test } from "test/L2/FeeVault.t.sol"; +import { Types } from "src/libraries/Types.sol"; /// @title OperatorFeeVault_Uncategorized_Test /// @notice Test contract for the OperatorFeeVault contract's functionality @@ -18,5 +19,6 @@ contract OperatorFeeVault_Uncategorized_Test is FeeVault_Uncategorized_Test { feeVaultName = "OperatorFeeVault"; minWithdrawalAmount = deploy.cfg().operatorFeeVaultMinimumWithdrawalAmount(); feeVault = IFeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)); + withdrawalNetwork = Types.WithdrawalNetwork(uint8(deploy.cfg().operatorFeeVaultWithdrawalNetwork())); } } diff --git a/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol b/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol index 48716635b8b..5ef59377710 100644 --- a/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol @@ -8,6 +8,7 @@ import { ISequencerFeeVault } from "interfaces/L2/ISequencerFeeVault.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; import { FeeVault_Uncategorized_Test } from "test/L2/FeeVault.t.sol"; +import { Types } from "src/libraries/Types.sol"; /// @title SequencerFeeVault_Uncategorized_Test /// @notice Test contract for the SequencerFeeVault contract's functionality @@ -19,6 +20,7 @@ contract SequencerFeeVault_Uncategorized_Test is FeeVault_Uncategorized_Test { feeVaultName = "SequencerFeeVault"; minWithdrawalAmount = deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(); feeVault = IFeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)); + withdrawalNetwork = Types.WithdrawalNetwork(uint8(deploy.cfg().sequencerFeeVaultWithdrawalNetwork())); } function test_constructor_l1FeeWallet_succeeds() external view { diff --git a/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol b/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol index 51c2fce2667..b12bade2a9f 100644 --- a/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol +++ b/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol @@ -5,6 +5,9 @@ import { Test } from "forge-std/Test.sol"; import { IOptimismSuperchainERC20 } from "interfaces/L2/IOptimismSuperchainERC20.sol"; import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; +import { Types } from "src/libraries/Types.sol"; + /// @title InitializerOZv5_Test /// @dev Ensures that the `initialize()` function on contracts cannot be called more than /// once. Tests the contracts inheriting from `Initializable` from OpenZeppelin Contracts v5. @@ -41,6 +44,58 @@ contract InitializerOZv5_Test is Test { initCalldata: abi.encodeCall(IOptimismSuperchainERC20.initialize, (address(0), "", "", 18)) }) ); + + // BaseFeeVault + contracts.push( + InitializeableContract({ + target: address( + DeployUtils.create1({ + _name: "BaseFeeVault", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IFeeVault.__constructor__, ())) + }) + ), + initCalldata: abi.encodeCall(IFeeVault.initialize, (address(0), 0, Types.WithdrawalNetwork.L1)) + }) + ); + + // OperatorFeeVault + contracts.push( + InitializeableContract({ + target: address( + DeployUtils.create1({ + _name: "OperatorFeeVault", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IFeeVault.__constructor__, ())) + }) + ), + initCalldata: abi.encodeCall(IFeeVault.initialize, (address(0), 0, Types.WithdrawalNetwork.L1)) + }) + ); + + // SequencerFeeVault + contracts.push( + InitializeableContract({ + target: address( + DeployUtils.create1({ + _name: "SequencerFeeVault", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IFeeVault.__constructor__, ())) + }) + ), + initCalldata: abi.encodeCall(IFeeVault.initialize, (address(0), 0, Types.WithdrawalNetwork.L1)) + }) + ); + + // L1FeeVault + contracts.push( + InitializeableContract({ + target: address( + DeployUtils.create1({ + _name: "L1FeeVault", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IFeeVault.__constructor__, ())) + }) + ), + initCalldata: abi.encodeCall(IFeeVault.initialize, (address(0), 0, Types.WithdrawalNetwork.L1)) + }) + ); } /// @notice Tests that: