From bdd554f5fb9a3cba9b706498e12ba24f8e7928fd Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Fri, 8 Aug 2025 09:28:17 -0500 Subject: [PATCH 01/23] feat: update fee vaults --- .../contracts-bedrock/src/L2/BaseFeeVault.sol | 16 ++- .../contracts-bedrock/src/L2/FeeSplitter.sol | 6 +- .../contracts-bedrock/src/L2/FeeVault.sol | 133 ++++++++++++------ .../contracts-bedrock/src/L2/L1FeeVault.sol | 16 ++- .../src/L2/OperatorFeeVault.sol | 11 +- .../src/L2/SequencerFeeVault.sol | 18 ++- .../src/legacy/FeeVaultInitializer.sol | 124 ++++++++++++++++ .../test/L2/FeeSplitter.t.sol | 24 ++-- 8 files changed, 273 insertions(+), 75 deletions(-) create mode 100644 packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index 91f8e0d93b4..42e58cb82d3 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -16,18 +16,24 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The BaseFeeVault accumulates the base fee that is paid by transactions. contract BaseFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.5.1 - string public constant version = "1.5.1"; + /// @custom:semver 1.6.0 + string public constant version = "1.6.0"; /// @notice Constructs the BaseFeeVault contract. + constructor() FeeVault() { } + + /// @notice Initializes 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( + function initialize( address _recipient, uint256 _minWithdrawalAmount, Types.WithdrawalNetwork _withdrawalNetwork ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } + external + reinitializer(1) + { + __FeeVault_init(_recipient, _minWithdrawalAmount, _withdrawalNetwork); + } } diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index 1bd9658bec0..fa090cf8f3a 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -345,13 +345,13 @@ contract FeeSplitter is ISemver, Initializable { /// /// @param _feeVault The address of the FeeVault to withdraw from. function _feeVaultWithdrawal(address payable _feeVault) internal { - if (FeeVault(_feeVault).WITHDRAWAL_NETWORK() != Types.WithdrawalNetwork.L2) { + if (FeeVault(_feeVault).withdrawalNetwork() != Types.WithdrawalNetwork.L2) { revert FeeSplitter_FeeVaultMustWithdrawToL2(); } - if (FeeVault(_feeVault).RECIPIENT() != address(this)) { + if (FeeVault(_feeVault).recipient() != address(this)) { revert FeeSplitter_FeeVaultMustWithdrawToFeeSplitter(); } - if (_feeVault.balance >= FeeVault(_feeVault).MIN_WITHDRAWAL_AMOUNT()) { + if (_feeVault.balance >= FeeVault(_feeVault).minWithdrawalAmount()) { FeeVault(_feeVault).withdraw(); } } diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 86c94fc3f6d..e50e35da3ea 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -11,36 +11,31 @@ import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; +// Base contracts +import { ProxyAdminOwnedBase } from "src/L1/ProxyAdminOwnedBase.sol"; +import { Initializable } from "@openzeppelin/contracts/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 { - /// @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; - +abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { /// @notice The minimum gas limit for the FeeVault withdrawal transaction. uint32 internal constant WITHDRAWAL_MIN_GAS = 400_000; /// @notice Total amount of wei processed by the contract. uint256 public totalProcessed; - /// @notice Reserve extra slots in the storage layout for future upgrades. - uint256[48] private __gap; + /// @notice Minimum balance before a withdrawal can be triggered. + uint256 public minWithdrawalAmount; + + /// @notice Account that will receive the fees. Can be located on L1 or L2. + address public recipient; + + /// @notice Network which the recipient will receive fees on. + Types.WithdrawalNetwork public withdrawalNetwork; + + /// @notice Reserve extra slots in the storage layout for future upgrades, 50 in total. + uint256[46] private __gap; /// @notice Emitted each time a withdrawal occurs. This event will be deprecated /// in favor of the Withdrawal event containing the WithdrawalNetwork parameter. @@ -56,52 +51,104 @@ abstract contract FeeVault { /// @param withdrawalNetwork Network which the to address will receive funds on. event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); - /// @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 Emitted when the minimum withdrawal amount for the vault is updated. + /// @param oldWithdrawalAmount The previous minimum withdrawal amount. + /// @param newWithdrawalAmount The new minimum withdrawal amount. + event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount); + + /// @notice Emitted when the fee recipient for this vault is updated. + /// @param oldRecipient The previous recipient address. + /// @param newRecipient The new recipient address. + event RecipientUpdated(address oldRecipient, address newRecipient); + + /// @notice Emitted when the withdrawal network for this vault is updated. + /// @param oldWithdrawalNetwork The previous withdrawal network. + /// @param newWithdrawalNetwork The new withdrawal network. + event WithdrawalNetworkUpdated( + Types.WithdrawalNetwork oldWithdrawalNetwork, Types.WithdrawalNetwork newWithdrawalNetwork + ); + + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the FeeVault with the current configuration. + /// @param _newRecipient Wallet that will receive the fees. + /// @param _newMinWithdrawalAmount Minimum balance for withdrawals. + /// @param _newWithdrawalNetwork Network which the recipient will receive fees on. + function __FeeVault_init( + address _newRecipient, + uint256 _newMinWithdrawalAmount, + Types.WithdrawalNetwork _newWithdrawalNetwork + ) + public + onlyInitializing + { + _assertOnlyProxyAdminOwner(); + + recipient = _newRecipient; + minWithdrawalAmount = _newMinWithdrawalAmount; + withdrawalNetwork = _newWithdrawalNetwork; } /// @notice Allow the contract to receive ETH. receive() external payable { } - /// @notice Minimum balance before a withdrawal can be triggered. - function minWithdrawalAmount() public view returns (uint256 amount_) { - amount_ = MIN_WITHDRAWAL_AMOUNT; + /// @notice Updates the minimum amount of funds the SequencerFeeVault contract must hold before they can be + /// withdrawn. + /// @param _newMinWithdrawalAmount The new minimum withdrawal amount. + function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) external { + _assertOnlyProxyAdminOwner(); + + uint256 oldWithdrawalAmount = minWithdrawalAmount; + minWithdrawalAmount = _newMinWithdrawalAmount; + + emit MinWithdrawalAmountUpdated(oldWithdrawalAmount, _newMinWithdrawalAmount); } - /// @notice Account that will receive the fees. Can be located on L1 or L2. - function recipient() public view returns (address recipient_) { - recipient_ = RECIPIENT; + /// @notice Updates the recipient of sequencer fees when they are withdrawn from the vault. + /// @param _newRecipient The new recipient address. + function setRecipient(address _newRecipient) external { + _assertOnlyProxyAdminOwner(); + + address oldRecipient = recipient; + recipient = _newRecipient; + + emit RecipientUpdated(oldRecipient, _newRecipient); } - /// @notice Network which the recipient will receive fees on. - function withdrawalNetwork() public view returns (Types.WithdrawalNetwork network_) { - network_ = WITHDRAWAL_NETWORK; + /// @notice Updates the network to which sequencer fees will be withdrawn. This can be either WithdrawalNetwork.L1 + /// to withdraw them to an address on L1 by using the L2ToL1MessagePasser predeploy, or WithdrawalNetwork.L2 to + /// withdraw them to an address on the same chain. + /// @param _newWithdrawalNetwork The new withdrawal network. + function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external { + _assertOnlyProxyAdminOwner(); + + Types.WithdrawalNetwork oldWithdrawalNetwork = withdrawalNetwork; + withdrawalNetwork = _newWithdrawalNetwork; + + emit WithdrawalNetworkUpdated(oldWithdrawalNetwork, _newWithdrawalNetwork); } /// @notice Triggers a withdrawal of funds to the fee wallet on L1 or L2. function withdraw() external { require( - address(this).balance >= MIN_WITHDRAWAL_AMOUNT, + address(this).balance >= minWithdrawalAmount, "FeeVault: withdrawal amount must be greater than minimum withdrawal amount" ); uint256 value = address(this).balance; totalProcessed += value; - emit Withdrawal(value, RECIPIENT, msg.sender); - emit Withdrawal(value, RECIPIENT, msg.sender, WITHDRAWAL_NETWORK); + emit Withdrawal(value, recipient, msg.sender); + emit Withdrawal(value, recipient, msg.sender, withdrawalNetwork); - if (WITHDRAWAL_NETWORK == 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, + _target: recipient, _gasLimit: WITHDRAWAL_MIN_GAS, _data: hex"" }); diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index de1a212b5e9..a1f753b4f3b 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -16,18 +16,24 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The L1FeeVault accumulates the L1 portion of the transaction fees. contract L1FeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.5.1 - string public constant version = "1.5.1"; + /// @custom:semver 1.6.0 + string public constant version = "1.6.0"; /// @notice Constructs the L1FeeVault contract. + constructor() FeeVault() { } + + /// @notice Initializes 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( + function initialize( address _recipient, uint256 _minWithdrawalAmount, Types.WithdrawalNetwork _withdrawalNetwork ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } + external + reinitializer(1) + { + __FeeVault_init(_recipient, _minWithdrawalAmount, _withdrawalNetwork); + } } diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol index b7341824d6f..4d4b4727410 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -17,10 +17,15 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The OperatorFeeVault accumulates the operator portion of the transaction fees. contract OperatorFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.0.0 - string public constant version = "1.0.0"; + /// @custom:semver 1.1.0 + string public constant version = "1.1.0"; /// @notice Constructs the OperatorFeeVault contract. + constructor() FeeVault() { } + + /// @notice Initializes the OperatorFeeVault contract. /// Funds are withdrawn to the base fee vault on the L2 network. - constructor() FeeVault(Predeploys.BASE_FEE_VAULT, 0, Types.WithdrawalNetwork.L2) { } + function initialize() external reinitializer(1) { + __FeeVault_init(Predeploys.BASE_FEE_VAULT, 0, Types.WithdrawalNetwork.L2); + } } diff --git a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol index 0b4401deed4..7cca9e071c9 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -16,25 +16,31 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The SequencerFeeVault is the contract that holds any fees paid to the Sequencer during /// transaction processing and block production. contract SequencerFeeVault is FeeVault, ISemver { - /// @custom:semver 1.5.1 - string public constant version = "1.5.1"; + /// @custom:semver 1.6.0 + string public constant version = "1.6.0"; /// @notice Constructs the SequencerFeeVault contract. + constructor() FeeVault() { } + + /// @notice Initializes 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( + function initialize( address _recipient, uint256 _minWithdrawalAmount, Types.WithdrawalNetwork _withdrawalNetwork ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } + external + reinitializer(1) + { + __FeeVault_init(_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/src/legacy/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol new file mode 100644 index 00000000000..800cefdb591 --- /dev/null +++ b/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { FeeVault } from "src/L2/FeeVault.sol"; +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 { IProxy } from "interfaces/universal/IProxy.sol"; + +/// @title FeeVaultInitializer +/// @notice This contract migrates the fee vaults from the legacy system to the new system. +contract FeeVaultInitializer is ISemver { + /// @notice Semantic version. + /// @custom:semver 1.0.0 + string public constant version = "1.0.0"; + + /// @notice Constructs the FeeVaultMigrator contract. + constructor() { } + + function migrate() public { + _migrateBaseFeeVault(); + _migrateSequencerFeeVault(); + _migrateL1FeeVault(); + _migrateOperatorFeeVault(); + } + + function _migrateBaseFeeVault() internal { + // Grab current values from the old fee vault + address currentBaseFeeVaultRecipient = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).recipient(); + Types.WithdrawalNetwork currentBaseFeeVaultWithdrawalNetwork = + FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork(); + uint256 currentBaseFeeVaultMinWithdrawalAmount = + FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount(); + + // Withdraw funds from the old fee vaults + FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdraw(); + + // Deploy new implementation + BaseFeeVault newBaseFeeVault = new BaseFeeVault(); + + // Upgrade the proxy and initialize the new implementation + IProxy(payable(Predeploys.BASE_FEE_VAULT)).upgradeToAndCall( + address(newBaseFeeVault), + abi.encodeWithSelector( + BaseFeeVault.initialize.selector, + currentBaseFeeVaultRecipient, + currentBaseFeeVaultMinWithdrawalAmount, + currentBaseFeeVaultWithdrawalNetwork + ) + ); + } + + function _migrateSequencerFeeVault() internal { + // Grab current values from the old fee vault + address currentSequencerFeeVaultRecipient = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).recipient(); + Types.WithdrawalNetwork currentSequencerFeeVaultWithdrawalNetwork = + FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork(); + uint256 currentSequencerFeeVaultMinWithdrawalAmount = + FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount(); + + // Withdraw funds from the old fee vaults + FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdraw(); + + // Deploy new implementation + SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(); + + // Upgrade the proxy and initialize the new implementation + IProxy(payable(Predeploys.SEQUENCER_FEE_WALLET)).upgradeToAndCall( + address(newSequencerFeeVault), + abi.encodeWithSelector( + SequencerFeeVault.initialize.selector, + currentSequencerFeeVaultRecipient, + currentSequencerFeeVaultMinWithdrawalAmount, + currentSequencerFeeVaultWithdrawalNetwork + ) + ); + } + + function _migrateL1FeeVault() internal { + // Grab current values from the old fee vault + address currentL1FeeVaultRecipient = FeeVault(payable(Predeploys.L1_FEE_VAULT)).recipient(); + Types.WithdrawalNetwork currentL1FeeVaultWithdrawalNetwork = + FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork(); + uint256 currentL1FeeVaultMinWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount(); + + // Withdraw funds from the old fee vaults + FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdraw(); + + // Deploy new implementation + L1FeeVault newL1FeeVault = new L1FeeVault(); + + // Upgrade the proxy and initialize the new implementation + IProxy(payable(Predeploys.L1_FEE_VAULT)).upgradeToAndCall( + address(newL1FeeVault), + abi.encodeWithSelector( + L1FeeVault.initialize.selector, + currentL1FeeVaultRecipient, + currentL1FeeVaultMinWithdrawalAmount, + currentL1FeeVaultWithdrawalNetwork + ) + ); + } + + function _migrateOperatorFeeVault() internal { + // Withdraw funds from the old fee vaults + FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).withdraw(); + + // Deploy new implementation Note this has hardcoded parameters in the constructor that initialize the feevault + OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(); + + // Upgrade the proxy and initialize the new implementation + IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).upgradeToAndCall( + address(newOperatorFeeVault), abi.encodeWithSelector(OperatorFeeVault.initialize.selector) + ); + } +} diff --git a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol index 4957aa72f36..fc0dd7a320e 100644 --- a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol @@ -50,10 +50,10 @@ contract FeeSplitterTest is CommonTest { _owner = ProxyAdmin(Predeploys.PROXY_ADMIN).owner(); // Deploy fee recipient A - _configuredShareRecipient = address(new Mock_ConfiguredShareRecipient()); + _configuredShareRecipient = makeAddr("configuredShareRecipient"); // Deploy fee recipient B - _remainderRecipient = address(new Mock_RemainderRecipient()); + _remainderRecipient = makeAddr("remainderRecipient"); } function _initializeFeeSplitter() internal { @@ -389,14 +389,6 @@ contract FeeSplitterTest is CommonTest { } } -contract Mock_ConfiguredShareRecipient { - receive() external payable { } -} - -contract Mock_RemainderRecipient { - receive() external payable { } -} - contract Mock_FeeVault { uint256 public immutable MIN_WITHDRAWAL_AMOUNT; address public immutable RECIPIENT; @@ -431,4 +423,16 @@ contract Mock_FeeVault { require(success, "FeeVault: failed to send ETH to L2 fee recipient"); } } + + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork) { + return WITHDRAWAL_NETWORK; + } + + function minWithdrawalAmount() external view returns (uint256) { + return MIN_WITHDRAWAL_AMOUNT; + } + + function recipient() external view returns (address) { + return RECIPIENT; + } } From 200ea5898af28b13ced6f1d5f78d87fde690757d Mon Sep 17 00:00:00 2001 From: Funkornaut <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:14:30 -0500 Subject: [PATCH 02/23] Update packages/contracts-bedrock/src/L2/OperatorFeeVault.sol Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> Signed-off-by: Funkornaut <107587461+funkornaut001@users.noreply.github.com> --- packages/contracts-bedrock/src/L2/OperatorFeeVault.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol index 4d4b4727410..684a4a9e953 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -21,7 +21,6 @@ contract OperatorFeeVault is FeeVault, ISemver { string public constant version = "1.1.0"; /// @notice Constructs the OperatorFeeVault contract. - constructor() FeeVault() { } /// @notice Initializes the OperatorFeeVault contract. /// Funds are withdrawn to the base fee vault on the L2 network. From 32e0798667b121643b39158809255f0c43b47487 Mon Sep 17 00:00:00 2001 From: Funkornaut <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:14:48 -0500 Subject: [PATCH 03/23] Update packages/contracts-bedrock/src/L2/L1FeeVault.sol Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> Signed-off-by: Funkornaut <107587461+funkornaut001@users.noreply.github.com> --- packages/contracts-bedrock/src/L2/L1FeeVault.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index a1f753b4f3b..1aa108eb79d 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -20,7 +20,6 @@ contract L1FeeVault is FeeVault, ISemver { string public constant version = "1.6.0"; /// @notice Constructs the L1FeeVault contract. - constructor() FeeVault() { } /// @notice Initializes the L1FeeVault contract. /// @param _recipient Wallet that will receive the fees. From 508c2ad0cd039ea356a461a80096c635e722a97a Mon Sep 17 00:00:00 2001 From: Funkornaut <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:14:55 -0500 Subject: [PATCH 04/23] Update packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> Signed-off-by: Funkornaut <107587461+funkornaut001@users.noreply.github.com> --- packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol index 800cefdb591..db52f22dff4 100644 --- a/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol @@ -23,7 +23,6 @@ contract FeeVaultInitializer is ISemver { string public constant version = "1.0.0"; /// @notice Constructs the FeeVaultMigrator contract. - constructor() { } function migrate() public { _migrateBaseFeeVault(); From ee6ef13d1b647e8fc094e8ca6326c5df526005e2 Mon Sep 17 00:00:00 2001 From: Funkornaut <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:15:02 -0500 Subject: [PATCH 05/23] Update packages/contracts-bedrock/src/L2/SequencerFeeVault.sol Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> Signed-off-by: Funkornaut <107587461+funkornaut001@users.noreply.github.com> --- packages/contracts-bedrock/src/L2/SequencerFeeVault.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol index 7cca9e071c9..ae53a60a630 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -20,7 +20,6 @@ contract SequencerFeeVault is FeeVault, ISemver { string public constant version = "1.6.0"; /// @notice Constructs the SequencerFeeVault contract. - constructor() FeeVault() { } /// @notice Initializes the SequencerFeeVault contract. /// @param _recipient Wallet that will receive the fees. From e1b5a4f5acb88d5117d220be78923c4a6fc3a942 Mon Sep 17 00:00:00 2001 From: Funkornaut <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:15:08 -0500 Subject: [PATCH 06/23] Update packages/contracts-bedrock/src/L2/BaseFeeVault.sol Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> Signed-off-by: Funkornaut <107587461+funkornaut001@users.noreply.github.com> --- packages/contracts-bedrock/src/L2/BaseFeeVault.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index 42e58cb82d3..49f976955d6 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -20,7 +20,6 @@ contract BaseFeeVault is FeeVault, ISemver { string public constant version = "1.6.0"; /// @notice Constructs the BaseFeeVault contract. - constructor() FeeVault() { } /// @notice Initializes the BaseFeeVault contract. /// @param _recipient Wallet that will receive the fees. From b5b866813f9f8534ead5149bb515edf6a30633e8 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Thu, 14 Aug 2025 19:00:10 -0500 Subject: [PATCH 07/23] feat: add events --- .../{legacy => L2}/FeeVaultInitializer.sol | 112 +++++++++++++++--- 1 file changed, 97 insertions(+), 15 deletions(-) rename packages/contracts-bedrock/src/{legacy => L2}/FeeVaultInitializer.sol (51%) diff --git a/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol similarity index 51% rename from packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol rename to packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index db52f22dff4..5713555dff5 100644 --- a/packages/contracts-bedrock/src/legacy/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.15; import { FeeVault } from "src/L2/FeeVault.sol"; import { BaseFeeVault } from "src/L2/BaseFeeVault.sol"; @@ -18,13 +18,69 @@ import { IProxy } from "interfaces/universal/IProxy.sol"; /// @title FeeVaultInitializer /// @notice This contract migrates the fee vaults from the legacy system to the new system. contract FeeVaultInitializer is ISemver { + /// @notice Semantic version. /// @custom:semver 1.0.0 string public constant version = "1.0.0"; - /// @notice Constructs the FeeVaultMigrator contract. - - function migrate() public { + /// @notice Emitted when the Sequencer Fee Vault is migrated. + /// @param oldImplementation The previous implementation address. + /// @param newImplementation The new implementation address. + /// @param recipient The recipient address for the new implementation. + /// @param network The withdrawal network for the new implementation. + /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. + event SequencerFeeVaultUpgraded( + address indexed oldImplementation, + address indexed newImplementation, + address recipient, + Types.WithdrawalNetwork network, + uint256 minWithdrawalAmount + ); + + /// @notice Emitted when the L1 Fee Vault is migrated. + /// @param oldImplementation The previous implementation address. + /// @param newImplementation The new implementation address. + /// @param recipient The recipient address for the new implementation. + /// @param network The withdrawal network for the new implementation. + /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. + event L1FeeVaultUpgraded( + address indexed oldImplementation, + address indexed newImplementation, + address recipient, + Types.WithdrawalNetwork network, + uint256 minWithdrawalAmount + ); + + /// @notice Emitted when the Base Fee Vault is migrated. + /// @param oldImplementation The previous implementation address. + /// @param newImplementation The new implementation address. + /// @param recipient The recipient address for the new implementation. + /// @param network The withdrawal network for the new implementation. + /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. + event BaseFeeVaultUpgraded( + address indexed oldImplementation, + address indexed newImplementation, + address recipient, + Types.WithdrawalNetwork network, + uint256 minWithdrawalAmount + ); + + /// @notice Emitted when the Operator Fee Vault is migrated. + /// @param oldImplementation The previous implementation address. + /// @param newImplementation The new implementation address. + /// @param recipient The recipient address for the new implementation. + /// @param network The withdrawal network for the new implementation. + /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. + event OperatorFeeVaultUpgraded( + address indexed oldImplementation, + address indexed newImplementation, + address recipient, + Types.WithdrawalNetwork network, + uint256 minWithdrawalAmount + ); + + /// @notice Migrates all fee vaults to their new implementations. + function migrate() external { _migrateBaseFeeVault(); _migrateSequencerFeeVault(); _migrateL1FeeVault(); @@ -38,9 +94,7 @@ contract FeeVaultInitializer is ISemver { FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork(); uint256 currentBaseFeeVaultMinWithdrawalAmount = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount(); - - // Withdraw funds from the old fee vaults - FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdraw(); + address currentImplementation = IProxy(payable(Predeploys.BASE_FEE_VAULT)).implementation(); // Deploy new implementation BaseFeeVault newBaseFeeVault = new BaseFeeVault(); @@ -55,6 +109,14 @@ contract FeeVaultInitializer is ISemver { currentBaseFeeVaultWithdrawalNetwork ) ); + + emit BaseFeeVaultUpgraded( + currentImplementation, + address(newBaseFeeVault), + currentBaseFeeVaultRecipient, + currentBaseFeeVaultWithdrawalNetwork, + currentBaseFeeVaultMinWithdrawalAmount + ); } function _migrateSequencerFeeVault() internal { @@ -64,9 +126,7 @@ contract FeeVaultInitializer is ISemver { FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork(); uint256 currentSequencerFeeVaultMinWithdrawalAmount = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount(); - - // Withdraw funds from the old fee vaults - FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdraw(); + address currentImplementation = IProxy(payable(Predeploys.SEQUENCER_FEE_WALLET)).implementation(); // Deploy new implementation SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(); @@ -81,6 +141,14 @@ contract FeeVaultInitializer is ISemver { currentSequencerFeeVaultWithdrawalNetwork ) ); + + emit SequencerFeeVaultUpgraded( + currentImplementation, + address(newSequencerFeeVault), + currentSequencerFeeVaultRecipient, + currentSequencerFeeVaultWithdrawalNetwork, + currentSequencerFeeVaultMinWithdrawalAmount + ); } function _migrateL1FeeVault() internal { @@ -89,9 +157,7 @@ contract FeeVaultInitializer is ISemver { Types.WithdrawalNetwork currentL1FeeVaultWithdrawalNetwork = FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork(); uint256 currentL1FeeVaultMinWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount(); - - // Withdraw funds from the old fee vaults - FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdraw(); + address currentImplementation = IProxy(payable(Predeploys.L1_FEE_VAULT)).implementation(); // Deploy new implementation L1FeeVault newL1FeeVault = new L1FeeVault(); @@ -106,11 +172,19 @@ contract FeeVaultInitializer is ISemver { currentL1FeeVaultWithdrawalNetwork ) ); + + emit L1FeeVaultUpgraded( + currentImplementation, + address(newL1FeeVault), + currentL1FeeVaultRecipient, + currentL1FeeVaultWithdrawalNetwork, + currentL1FeeVaultMinWithdrawalAmount + ); } function _migrateOperatorFeeVault() internal { - // Withdraw funds from the old fee vaults - FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).withdraw(); + // Grab current implementation for the event + address currentImplementation = IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).implementation(); // Deploy new implementation Note this has hardcoded parameters in the constructor that initialize the feevault OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(); @@ -119,5 +193,13 @@ contract FeeVaultInitializer is ISemver { IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).upgradeToAndCall( address(newOperatorFeeVault), abi.encodeWithSelector(OperatorFeeVault.initialize.selector) ); + + emit OperatorFeeVaultUpgraded( + currentImplementation, + address(newOperatorFeeVault), + newOperatorFeeVault.recipient(), + newOperatorFeeVault.withdrawalNetwork(), + newOperatorFeeVault.minWithdrawalAmount() + ); } } From 03350e3839190fa5897abb4e43cb1ac8e4205bd7 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:32:33 -0500 Subject: [PATCH 08/23] feat: immutable and state vars with proper view and setter functions --- .../contracts-bedrock/src/L2/FeeVault.sol | 125 +++++++++++++++--- 1 file changed, 105 insertions(+), 20 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index e50e35da3ea..6a5126ad1bd 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -19,23 +19,50 @@ import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable /// @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 is ProxyAdminOwnedBase, Initializable { + /// @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; + /// @notice Flag positions for configuration tracking. + uint8 private constant RECIPIENT_FLAG = 0; + uint8 private constant MIN_WITHDRAWAL_AMOUNT_FLAG = 1; + uint8 private constant WITHDRAWAL_NETWORK_FLAG = 2; + /// @notice Total amount of wei processed by the contract. uint256 public totalProcessed; /// @notice Minimum balance before a withdrawal can be triggered. - uint256 public minWithdrawalAmount; + uint256 internal _minWithdrawalAmount; /// @notice Account that will receive the fees. Can be located on L1 or L2. - address public recipient; + address internal _recipient; /// @notice Network which the recipient will receive fees on. - Types.WithdrawalNetwork public withdrawalNetwork; + Types.WithdrawalNetwork internal _withdrawalNetwork; + + /// @notice Configuration flags to track which values have been set by the owner. + /// @dev Bit 0: ownerSetRecipient, Bit 1: ownerSetMinWithdrawalAmount, Bit 2: ownerSetWithdrawalNetwork + uint8 private _configFlags; /// @notice Reserve extra slots in the storage layout for future upgrades, 50 in total. - uint256[46] private __gap; + uint256[43] private __gap; /// @notice Emitted each time a withdrawal occurs. This event will be deprecated /// in favor of the Withdrawal event containing the WithdrawalNetwork parameter. @@ -68,8 +95,31 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { Types.WithdrawalNetwork oldWithdrawalNetwork, Types.WithdrawalNetwork newWithdrawalNetwork ); - constructor() { + /// @param _currentRecipient Wallet that will receive the fees. + /// @param _currentMinWithdrawalAmount Minimum balance for withdrawals. + /// @param _currentWithdrawalNetwork Network which the recipient will receive fees on. + constructor( + address _currentRecipient, + uint256 _currentMinWithdrawalAmount, + Types.WithdrawalNetwork _currentWithdrawalNetwork + ) { _disableInitializers(); + RECIPIENT = _currentRecipient; + MIN_WITHDRAWAL_AMOUNT = _currentMinWithdrawalAmount; + WITHDRAWAL_NETWORK = _currentWithdrawalNetwork; + } + + /// @notice Sets a configuration flag to indicate a value has been set by the owner. + /// @param flagPosition The bit position of the flag to set. + function _setConfigFlag(uint8 flagPosition) internal { + _configFlags |= uint8(1 << flagPosition); + } + + /// @notice Checks if a configuration flag is set. + /// @param flagPosition The bit position of the flag to check. + /// @return True if the flag is set, false otherwise. + function _isConfigFlagSet(uint8 flagPosition) internal view returns (bool) { + return (_configFlags & uint8(1 << flagPosition)) != 0; } /// @notice Initializes the FeeVault with the current configuration. @@ -86,9 +136,14 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { { _assertOnlyProxyAdminOwner(); - recipient = _newRecipient; - minWithdrawalAmount = _newMinWithdrawalAmount; - withdrawalNetwork = _newWithdrawalNetwork; + _recipient = _newRecipient; + _minWithdrawalAmount = _newMinWithdrawalAmount; + _withdrawalNetwork = _newWithdrawalNetwork; + + // Set all configuration flags to indicate values have been set by initialization + _setConfigFlag(RECIPIENT_FLAG); + _setConfigFlag(MIN_WITHDRAWAL_AMOUNT_FLAG); + _setConfigFlag(WITHDRAWAL_NETWORK_FLAG); } /// @notice Allow the contract to receive ETH. @@ -100,8 +155,9 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) external { _assertOnlyProxyAdminOwner(); - uint256 oldWithdrawalAmount = minWithdrawalAmount; - minWithdrawalAmount = _newMinWithdrawalAmount; + uint256 oldWithdrawalAmount = _minWithdrawalAmount; + _minWithdrawalAmount = _newMinWithdrawalAmount; + _setConfigFlag(MIN_WITHDRAWAL_AMOUNT_FLAG); emit MinWithdrawalAmountUpdated(oldWithdrawalAmount, _newMinWithdrawalAmount); } @@ -111,8 +167,9 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { function setRecipient(address _newRecipient) external { _assertOnlyProxyAdminOwner(); - address oldRecipient = recipient; - recipient = _newRecipient; + address oldRecipient = _recipient; + _recipient = _newRecipient; + _setConfigFlag(RECIPIENT_FLAG); emit RecipientUpdated(oldRecipient, _newRecipient); } @@ -124,8 +181,9 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external { _assertOnlyProxyAdminOwner(); - Types.WithdrawalNetwork oldWithdrawalNetwork = withdrawalNetwork; - withdrawalNetwork = _newWithdrawalNetwork; + Types.WithdrawalNetwork oldWithdrawalNetwork = _withdrawalNetwork; + _withdrawalNetwork = _newWithdrawalNetwork; + _setConfigFlag(WITHDRAWAL_NETWORK_FLAG); emit WithdrawalNetworkUpdated(oldWithdrawalNetwork, _newWithdrawalNetwork); } @@ -133,25 +191,52 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { /// @notice Triggers a withdrawal of funds to the fee wallet on L1 or L2. function withdraw() external { require( - address(this).balance >= minWithdrawalAmount, + address(this).balance >= minWithdrawalAmount(), "FeeVault: withdrawal amount must be greater than minimum withdrawal amount" ); uint256 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, + _target: recipient(), _gasLimit: WITHDRAWAL_MIN_GAS, _data: hex"" }); } } + + function minWithdrawalAmount() public view returns (uint256) { + if (_isConfigFlagSet(MIN_WITHDRAWAL_AMOUNT_FLAG)) { + // If the flag is set, use the storage variable + return _minWithdrawalAmount; + } + // If the flag is not set, use the immutable + return MIN_WITHDRAWAL_AMOUNT; + } + + function recipient() public view returns (address) { + if (_isConfigFlagSet(RECIPIENT_FLAG)) { + // If the flag is set, use the storage variable + return _recipient; + } + // If the flag is not set, use the immutable + return RECIPIENT; + } + + function withdrawalNetwork() public view returns (Types.WithdrawalNetwork) { + if (_isConfigFlagSet(WITHDRAWAL_NETWORK_FLAG)) { + // If the flag is set, use the storage variable + return _withdrawalNetwork; + } + // If the flag is not set, use the immutable + return WITHDRAWAL_NETWORK; + } } From cccee26e56ee54bf32533b7dbcdc5f7e40b84ab1 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:59:51 -0500 Subject: [PATCH 09/23] feat: update vaults remove initializers --- .../contracts-bedrock/src/L2/BaseFeeVault.sol | 22 ++++---------- .../contracts-bedrock/src/L2/FeeVault.sol | 29 ++----------------- .../contracts-bedrock/src/L2/L1FeeVault.sol | 18 +++--------- .../src/L2/OperatorFeeVault.sol | 13 ++++----- .../src/L2/SequencerFeeVault.sol | 24 +++++---------- 5 files changed, 26 insertions(+), 80 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index 49f976955d6..c878441bc62 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -16,23 +16,13 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The BaseFeeVault accumulates the base fee that is paid by transactions. contract BaseFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.6.0 - string public constant version = "1.6.0"; + /// @custom:semver 1.5.2 + string public constant version = "1.5.2"; /// @notice Constructs the BaseFeeVault contract. + /// @param _currentRecipient Wallet that will receive the fees. + /// @param _currentMinWithdrawAmount Minimum balance for withdrawals. + /// @param _currentWithdrawNetwrok Network which the recipient will receive fees on. + constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwrok) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwrok) { } - /// @notice Initializes 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. - function initialize( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external - reinitializer(1) - { - __FeeVault_init(_recipient, _minWithdrawalAmount, _withdrawalNetwork); - } } diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 6a5126ad1bd..39fb821dd76 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -41,9 +41,9 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { uint32 internal constant WITHDRAWAL_MIN_GAS = 400_000; /// @notice Flag positions for configuration tracking. - uint8 private constant RECIPIENT_FLAG = 0; - uint8 private constant MIN_WITHDRAWAL_AMOUNT_FLAG = 1; - uint8 private constant WITHDRAWAL_NETWORK_FLAG = 2; + uint8 internal constant RECIPIENT_FLAG = 0; + uint8 internal constant MIN_WITHDRAWAL_AMOUNT_FLAG = 1; + uint8 internal constant WITHDRAWAL_NETWORK_FLAG = 2; /// @notice Total amount of wei processed by the contract. uint256 public totalProcessed; @@ -122,29 +122,6 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { return (_configFlags & uint8(1 << flagPosition)) != 0; } - /// @notice Initializes the FeeVault with the current configuration. - /// @param _newRecipient Wallet that will receive the fees. - /// @param _newMinWithdrawalAmount Minimum balance for withdrawals. - /// @param _newWithdrawalNetwork Network which the recipient will receive fees on. - function __FeeVault_init( - address _newRecipient, - uint256 _newMinWithdrawalAmount, - Types.WithdrawalNetwork _newWithdrawalNetwork - ) - public - onlyInitializing - { - _assertOnlyProxyAdminOwner(); - - _recipient = _newRecipient; - _minWithdrawalAmount = _newMinWithdrawalAmount; - _withdrawalNetwork = _newWithdrawalNetwork; - - // Set all configuration flags to indicate values have been set by initialization - _setConfigFlag(RECIPIENT_FLAG); - _setConfigFlag(MIN_WITHDRAWAL_AMOUNT_FLAG); - _setConfigFlag(WITHDRAWAL_NETWORK_FLAG); - } /// @notice Allow the contract to receive ETH. receive() external payable { } diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index 1aa108eb79d..8f8675fbd1e 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -16,23 +16,13 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The L1FeeVault accumulates the L1 portion of the transaction fees. contract L1FeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.6.0 - string public constant version = "1.6.0"; + /// @custom:semver 1.5.2 + string public constant version = "1.5.2"; /// @notice Constructs the L1FeeVault contract. - - /// @notice Initializes 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. - function initialize( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external - reinitializer(1) - { - __FeeVault_init(_recipient, _minWithdrawalAmount, _withdrawalNetwork); - } + constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwork) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwork) { } + } diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol index 684a4a9e953..9b6fa0392a6 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -17,14 +17,13 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The OperatorFeeVault accumulates the operator portion of the transaction fees. contract OperatorFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.1.0 - string public constant version = "1.1.0"; + /// @custom:semver 1.0.1 + string public constant version = "1.0.1"; /// @notice Constructs the OperatorFeeVault contract. + /// @param _currentRecipient Wallet that will receive the fees. + /// @param _currentMinWithdrawAmount Minimum balance for withdrawals. + /// @param _currentWithdrawNetwork Network which the recipient will receive fees on. + constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwork) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwork) { } - /// @notice Initializes the OperatorFeeVault contract. - /// Funds are withdrawn to the base fee vault on the L2 network. - function initialize() external reinitializer(1) { - __FeeVault_init(Predeploys.BASE_FEE_VAULT, 0, Types.WithdrawalNetwork.L2); - } } diff --git a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol index ae53a60a630..d63a54f013d 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -16,30 +16,20 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The SequencerFeeVault is the contract that holds any fees paid to the Sequencer during /// transaction processing and block production. contract SequencerFeeVault is FeeVault, ISemver { - /// @custom:semver 1.6.0 - string public constant version = "1.6.0"; + /// @custom:semver 1.5.2 + string public constant version = "1.5.2"; /// @notice Constructs the SequencerFeeVault contract. + /// @param _currentRecipient Wallet that will receive the fees. + /// @param _currentMinWithdrawAmount Minimum balance for withdrawals. + /// @param _currentWithdrawNetwork Network which the recipient will receive fees on. + constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwork) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwork) { } - /// @notice Initializes 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. - function initialize( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external - reinitializer(1) - { - __FeeVault_init(_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(); } } From c965793b994f3aa5e9c966ab46314c178fb0677b Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:26:46 -0500 Subject: [PATCH 10/23] feat: enforce withdraw network to be l2 if recipient if fee splitter --- packages/contracts-bedrock/src/L2/FeeVault.sol | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 39fb821dd76..8d5c936429d 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -19,6 +19,9 @@ import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable /// @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 is ProxyAdminOwnedBase, Initializable { + /// @notice Error thrown when the fee splitter is set as the recipient and the withdrawal network is not L2. + error FeeVault_MustHaveL2WithdrawalNetwork(); + /// @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. @@ -144,6 +147,10 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { function setRecipient(address _newRecipient) external { _assertOnlyProxyAdminOwner(); + if (_newRecipient == Predeploys.FEE_SPLITTER && withdrawalNetwork() != Types.WithdrawalNetwork.L2) { + revert FeeVault_MustHaveL2WithdrawalNetwork(); + } + address oldRecipient = _recipient; _recipient = _newRecipient; _setConfigFlag(RECIPIENT_FLAG); @@ -158,6 +165,10 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external { _assertOnlyProxyAdminOwner(); + if (recipient() == Predeploys.FEE_SPLITTER && _newWithdrawalNetwork == Types.WithdrawalNetwork.L1) { + revert FeeVault_MustHaveL2WithdrawalNetwork(); + } + Types.WithdrawalNetwork oldWithdrawalNetwork = _withdrawalNetwork; _withdrawalNetwork = _newWithdrawalNetwork; _setConfigFlag(WITHDRAWAL_NETWORK_FLAG); @@ -190,6 +201,8 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { } } + /// @notice Returns the minimum withdrawal amount for the vault. + /// @return The minimum withdrawal amount. function minWithdrawalAmount() public view returns (uint256) { if (_isConfigFlagSet(MIN_WITHDRAWAL_AMOUNT_FLAG)) { // If the flag is set, use the storage variable @@ -199,6 +212,8 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { return MIN_WITHDRAWAL_AMOUNT; } + /// @notice Returns the recipient of the fees. + /// @return The recipient address. function recipient() public view returns (address) { if (_isConfigFlagSet(RECIPIENT_FLAG)) { // If the flag is set, use the storage variable @@ -208,6 +223,8 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { return RECIPIENT; } + /// @notice Returns the withdrawal network for the vault. + /// @return The withdrawal network. function withdrawalNetwork() public view returns (Types.WithdrawalNetwork) { if (_isConfigFlagSet(WITHDRAWAL_NETWORK_FLAG)) { // If the flag is set, use the storage variable From 2e7776338c13da3b29296146a7ef2b276d0e845b Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:34:43 -0500 Subject: [PATCH 11/23] feat: vault initializer contract only deploys new fee vaults --- .../src/L2/FeeVaultInitializer.sol | 190 +++++++----------- .../contracts-bedrock/src/L2/L1FeeVault.sol | 8 +- 2 files changed, 79 insertions(+), 119 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index 5713555dff5..6d2e1e50ee3 100644 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -16,20 +16,20 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; /// @title FeeVaultInitializer -/// @notice This contract migrates the fee vaults from the legacy system to the new system. +/// @notice This contract deploys new fee vault implementations with current configurations as immutables. contract FeeVaultInitializer is ISemver { /// @notice Semantic version. /// @custom:semver 1.0.0 string public constant version = "1.0.0"; - /// @notice Emitted when the Sequencer Fee Vault is migrated. + /// @notice Emitted when the Base Fee Vault is deployed. /// @param oldImplementation The previous implementation address. - /// @param newImplementation The new implementation address. - /// @param recipient The recipient address for the new implementation. - /// @param network The withdrawal network for the new implementation. - /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. - event SequencerFeeVaultUpgraded( + /// @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 BaseFeeVaultDeployed( address indexed oldImplementation, address indexed newImplementation, address recipient, @@ -37,13 +37,13 @@ contract FeeVaultInitializer is ISemver { uint256 minWithdrawalAmount ); - /// @notice Emitted when the L1 Fee Vault is migrated. + /// @notice Emitted when the Sequencer Fee Vault is deployed. /// @param oldImplementation The previous implementation address. - /// @param newImplementation The new implementation address. - /// @param recipient The recipient address for the new implementation. - /// @param network The withdrawal network for the new implementation. - /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. - event L1FeeVaultUpgraded( + /// @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 SequencerFeeVaultDeployed( address indexed oldImplementation, address indexed newImplementation, address recipient, @@ -51,13 +51,13 @@ contract FeeVaultInitializer is ISemver { uint256 minWithdrawalAmount ); - /// @notice Emitted when the Base Fee Vault is migrated. + /// @notice Emitted when the L1 Fee Vault is deployed. /// @param oldImplementation The previous implementation address. - /// @param newImplementation The new implementation address. - /// @param recipient The recipient address for the new implementation. - /// @param network The withdrawal network for the new implementation. - /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. - event BaseFeeVaultUpgraded( + /// @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 L1FeeVaultDeployed( address indexed oldImplementation, address indexed newImplementation, address recipient, @@ -65,13 +65,13 @@ contract FeeVaultInitializer is ISemver { uint256 minWithdrawalAmount ); - /// @notice Emitted when the Operator Fee Vault is migrated. + /// @notice Emitted when the Operator Fee Vault is deployed. /// @param oldImplementation The previous implementation address. - /// @param newImplementation The new implementation address. - /// @param recipient The recipient address for the new implementation. - /// @param network The withdrawal network for the new implementation. - /// @param minWithdrawalAmount The minimum withdrawal amount for the new implementation. - event OperatorFeeVaultUpgraded( + /// @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 OperatorFeeVaultDeployed( address indexed oldImplementation, address indexed newImplementation, address recipient, @@ -79,127 +79,87 @@ contract FeeVaultInitializer is ISemver { uint256 minWithdrawalAmount ); - /// @notice Migrates all fee vaults to their new implementations. - function migrate() external { - _migrateBaseFeeVault(); - _migrateSequencerFeeVault(); - _migrateL1FeeVault(); - _migrateOperatorFeeVault(); + /// @notice Constructor that deploys new fee vault implementations with current values as immutables. + constructor() { + _deployBaseFeeVault(); + _deploySequencerFeeVault(); + _deployL1FeeVault(); + _deployOperatorFeeVault(); } - function _migrateBaseFeeVault() internal { - // Grab current values from the old fee vault - address currentBaseFeeVaultRecipient = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).recipient(); - Types.WithdrawalNetwork currentBaseFeeVaultWithdrawalNetwork = - FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork(); - uint256 currentBaseFeeVaultMinWithdrawalAmount = - FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount(); + function _deployBaseFeeVault() internal { + // Get current values from the existing fee vault + address recipient = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).recipient(); + Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork(); + uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount(); address currentImplementation = IProxy(payable(Predeploys.BASE_FEE_VAULT)).implementation(); - // Deploy new implementation - BaseFeeVault newBaseFeeVault = new BaseFeeVault(); + // Deploy new implementation with current values as immutables + BaseFeeVault newBaseFeeVault = new BaseFeeVault(recipient, minWithdrawalAmount, network); - // Upgrade the proxy and initialize the new implementation - IProxy(payable(Predeploys.BASE_FEE_VAULT)).upgradeToAndCall( - address(newBaseFeeVault), - abi.encodeWithSelector( - BaseFeeVault.initialize.selector, - currentBaseFeeVaultRecipient, - currentBaseFeeVaultMinWithdrawalAmount, - currentBaseFeeVaultWithdrawalNetwork - ) - ); - - emit BaseFeeVaultUpgraded( + emit BaseFeeVaultDeployed( currentImplementation, address(newBaseFeeVault), - currentBaseFeeVaultRecipient, - currentBaseFeeVaultWithdrawalNetwork, - currentBaseFeeVaultMinWithdrawalAmount + recipient, + network, + minWithdrawalAmount ); } - function _migrateSequencerFeeVault() internal { - // Grab current values from the old fee vault - address currentSequencerFeeVaultRecipient = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).recipient(); - Types.WithdrawalNetwork currentSequencerFeeVaultWithdrawalNetwork = - FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork(); - uint256 currentSequencerFeeVaultMinWithdrawalAmount = - FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount(); + function _deploySequencerFeeVault() internal { + // Get current values from the existing fee vault + address recipient = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).recipient(); + Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork(); + uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount(); address currentImplementation = IProxy(payable(Predeploys.SEQUENCER_FEE_WALLET)).implementation(); - // Deploy new implementation - SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(); - - // Upgrade the proxy and initialize the new implementation - IProxy(payable(Predeploys.SEQUENCER_FEE_WALLET)).upgradeToAndCall( - address(newSequencerFeeVault), - abi.encodeWithSelector( - SequencerFeeVault.initialize.selector, - currentSequencerFeeVaultRecipient, - currentSequencerFeeVaultMinWithdrawalAmount, - currentSequencerFeeVaultWithdrawalNetwork - ) - ); + // Deploy new implementation with current values as immutables + SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(recipient, minWithdrawalAmount, network); - emit SequencerFeeVaultUpgraded( + emit SequencerFeeVaultDeployed( currentImplementation, address(newSequencerFeeVault), - currentSequencerFeeVaultRecipient, - currentSequencerFeeVaultWithdrawalNetwork, - currentSequencerFeeVaultMinWithdrawalAmount + recipient, + network, + minWithdrawalAmount ); } - function _migrateL1FeeVault() internal { - // Grab current values from the old fee vault - address currentL1FeeVaultRecipient = FeeVault(payable(Predeploys.L1_FEE_VAULT)).recipient(); - Types.WithdrawalNetwork currentL1FeeVaultWithdrawalNetwork = - FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork(); - uint256 currentL1FeeVaultMinWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount(); + function _deployL1FeeVault() internal { + // Get current values from the existing fee vault + address recipient = FeeVault(payable(Predeploys.L1_FEE_VAULT)).recipient(); + Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork(); + uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount(); address currentImplementation = IProxy(payable(Predeploys.L1_FEE_VAULT)).implementation(); - // Deploy new implementation - L1FeeVault newL1FeeVault = new L1FeeVault(); + // Deploy new implementation with current values as immutables + L1FeeVault newL1FeeVault = new L1FeeVault(recipient, minWithdrawalAmount, network); - // Upgrade the proxy and initialize the new implementation - IProxy(payable(Predeploys.L1_FEE_VAULT)).upgradeToAndCall( - address(newL1FeeVault), - abi.encodeWithSelector( - L1FeeVault.initialize.selector, - currentL1FeeVaultRecipient, - currentL1FeeVaultMinWithdrawalAmount, - currentL1FeeVaultWithdrawalNetwork - ) - ); - - emit L1FeeVaultUpgraded( + emit L1FeeVaultDeployed( currentImplementation, address(newL1FeeVault), - currentL1FeeVaultRecipient, - currentL1FeeVaultWithdrawalNetwork, - currentL1FeeVaultMinWithdrawalAmount + recipient, + network, + minWithdrawalAmount ); } - function _migrateOperatorFeeVault() internal { - // Grab current implementation for the event + function _deployOperatorFeeVault() internal { + // Get current values from the existing fee vault + address recipient = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).recipient(); + Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).withdrawalNetwork(); + uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).minWithdrawalAmount(); address currentImplementation = IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).implementation(); - // Deploy new implementation Note this has hardcoded parameters in the constructor that initialize the feevault - OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(); - - // Upgrade the proxy and initialize the new implementation - IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).upgradeToAndCall( - address(newOperatorFeeVault), abi.encodeWithSelector(OperatorFeeVault.initialize.selector) - ); + // Deploy new implementation with current values as immutables + OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(recipient, minWithdrawalAmount, network); - emit OperatorFeeVaultUpgraded( + emit OperatorFeeVaultDeployed( currentImplementation, address(newOperatorFeeVault), - newOperatorFeeVault.recipient(), - newOperatorFeeVault.withdrawalNetwork(), - newOperatorFeeVault.minWithdrawalAmount() + recipient, + network, + minWithdrawalAmount ); } } diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index 8f8675fbd1e..9292bfc5baf 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -20,9 +20,9 @@ contract L1FeeVault is FeeVault, ISemver { string public constant version = "1.5.2"; /// @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 _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwork) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwork) { } + /// @param _currentRecipient Wallet that will receive the fees. + /// @param _currentMinWithdrawalAmount Minimum balance for withdrawals. + /// @param _currentWithdrawalNetwork Network which the recipient will receive fees on. + constructor(address _currentRecipient, uint256 _currentMinWithdrawalAmount, Types.WithdrawalNetwork _currentWithdrawalNetwork) FeeVault(_currentRecipient, _currentMinWithdrawalAmount, _currentWithdrawalNetwork) { } } From 440f10a303d70220a1e0e98ace1148e64084981a Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 20 Aug 2025 11:41:52 -0500 Subject: [PATCH 12/23] feat: add in try catch blocks to support old fee vault implementations --- .../src/L2/FeeVaultInitializer.sol | 112 ++++++++++++++++-- 1 file changed, 100 insertions(+), 12 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index 6d2e1e50ee3..e79d10062ba 100644 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -89,11 +89,33 @@ contract FeeVaultInitializer is ISemver { function _deployBaseFeeVault() internal { // Get current values from the existing fee vault - address recipient = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).recipient(); - Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork(); - uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount(); + address recipient; + Types.WithdrawalNetwork network; + uint256 minWithdrawalAmount; address currentImplementation = IProxy(payable(Predeploys.BASE_FEE_VAULT)).implementation(); + // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails + try FeeVault(payable(Predeploys.BASE_FEE_VAULT)).recipient() returns (address _recipient) { + recipient = _recipient; + } catch { + // Legacy implementation - try snake_case function + recipient = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).RECIPIENT(); + } + + try FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { + network = _network; + } catch { + // Legacy implementation - try snake_case function + network = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).WITHDRAWAL_NETWORK(); + } + + try FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { + minWithdrawalAmount = _minWithdrawalAmount; + } catch { + // Legacy implementation - try snake_case function + minWithdrawalAmount = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).MIN_WITHDRAWAL_AMOUNT(); + } + // Deploy new implementation with current values as immutables BaseFeeVault newBaseFeeVault = new BaseFeeVault(recipient, minWithdrawalAmount, network); @@ -108,11 +130,33 @@ contract FeeVaultInitializer is ISemver { function _deploySequencerFeeVault() internal { // Get current values from the existing fee vault - address recipient = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).recipient(); - Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork(); - uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount(); + address recipient; + Types.WithdrawalNetwork network; + uint256 minWithdrawalAmount; address currentImplementation = IProxy(payable(Predeploys.SEQUENCER_FEE_WALLET)).implementation(); + // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails + try FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).recipient() returns (address _recipient) { + recipient = _recipient; + } catch { + // Legacy implementation - try snake_case function + recipient = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).RECIPIENT(); + } + + try FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { + network = _network; + } catch { + // Legacy implementation - try snake_case function + network = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).WITHDRAWAL_NETWORK(); + } + + try FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { + minWithdrawalAmount = _minWithdrawalAmount; + } catch { + // Legacy implementation - try snake_case function + minWithdrawalAmount = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).MIN_WITHDRAWAL_AMOUNT(); + } + // Deploy new implementation with current values as immutables SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(recipient, minWithdrawalAmount, network); @@ -127,11 +171,33 @@ contract FeeVaultInitializer is ISemver { function _deployL1FeeVault() internal { // Get current values from the existing fee vault - address recipient = FeeVault(payable(Predeploys.L1_FEE_VAULT)).recipient(); - Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork(); - uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount(); + address recipient; + Types.WithdrawalNetwork network; + uint256 minWithdrawalAmount; address currentImplementation = IProxy(payable(Predeploys.L1_FEE_VAULT)).implementation(); + // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails + try FeeVault(payable(Predeploys.L1_FEE_VAULT)).recipient() returns (address _recipient) { + recipient = _recipient; + } catch { + // Legacy implementation - try snake_case function + recipient = FeeVault(payable(Predeploys.L1_FEE_VAULT)).RECIPIENT(); + } + + try FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { + network = _network; + } catch { + // Legacy implementation - try snake_case function + network = FeeVault(payable(Predeploys.L1_FEE_VAULT)).WITHDRAWAL_NETWORK(); + } + + try FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { + minWithdrawalAmount = _minWithdrawalAmount; + } catch { + // Legacy implementation - try snake_case function + minWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).MIN_WITHDRAWAL_AMOUNT(); + } + // Deploy new implementation with current values as immutables L1FeeVault newL1FeeVault = new L1FeeVault(recipient, minWithdrawalAmount, network); @@ -146,11 +212,33 @@ contract FeeVaultInitializer is ISemver { function _deployOperatorFeeVault() internal { // Get current values from the existing fee vault - address recipient = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).recipient(); - Types.WithdrawalNetwork network = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).withdrawalNetwork(); - uint256 minWithdrawalAmount = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).minWithdrawalAmount(); + address recipient; + Types.WithdrawalNetwork network; + uint256 minWithdrawalAmount; address currentImplementation = IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).implementation(); + // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails + try FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).recipient() returns (address _recipient) { + recipient = _recipient; + } catch { + // Legacy implementation - try snake_case function + recipient = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).RECIPIENT(); + } + + try FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { + network = _network; + } catch { + // Legacy implementation - try snake_case function + network = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).WITHDRAWAL_NETWORK(); + } + + try FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { + minWithdrawalAmount = _minWithdrawalAmount; + } catch { + // Legacy implementation - try snake_case function + minWithdrawalAmount = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).MIN_WITHDRAWAL_AMOUNT(); + } + // Deploy new implementation with current values as immutables OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(recipient, minWithdrawalAmount, network); From cc2d8b7c759a22f10fc64f1d34b19b6689addff8 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:57:32 -0500 Subject: [PATCH 13/23] feat: revert constructor changes --- .../contracts-bedrock/src/L2/BaseFeeVault.sol | 15 ++++++++++----- packages/contracts-bedrock/src/L2/L1FeeVault.sol | 15 ++++++++++----- .../contracts-bedrock/src/L2/OperatorFeeVault.sol | 15 ++++++++++----- .../src/L2/SequencerFeeVault.sol | 15 ++++++++++----- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index c878441bc62..84983c8c3b3 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -20,9 +20,14 @@ contract BaseFeeVault is FeeVault, ISemver { string public constant version = "1.5.2"; /// @notice Constructs the BaseFeeVault contract. - /// @param _currentRecipient Wallet that will receive the fees. - /// @param _currentMinWithdrawAmount Minimum balance for withdrawals. - /// @param _currentWithdrawNetwrok Network which the recipient will receive fees on. - constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwrok) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwrok) { } - + /// @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/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index 9292bfc5baf..a53eaf712c0 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -20,9 +20,14 @@ contract L1FeeVault is FeeVault, ISemver { string public constant version = "1.5.2"; /// @notice Constructs the L1FeeVault contract. - /// @param _currentRecipient Wallet that will receive the fees. - /// @param _currentMinWithdrawalAmount Minimum balance for withdrawals. - /// @param _currentWithdrawalNetwork Network which the recipient will receive fees on. - constructor(address _currentRecipient, uint256 _currentMinWithdrawalAmount, Types.WithdrawalNetwork _currentWithdrawalNetwork) FeeVault(_currentRecipient, _currentMinWithdrawalAmount, _currentWithdrawalNetwork) { } - + /// @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 9b6fa0392a6..7ef0b0164f2 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -21,9 +21,14 @@ contract OperatorFeeVault is FeeVault, ISemver { string public constant version = "1.0.1"; /// @notice Constructs the OperatorFeeVault contract. - /// @param _currentRecipient Wallet that will receive the fees. - /// @param _currentMinWithdrawAmount Minimum balance for withdrawals. - /// @param _currentWithdrawNetwork Network which the recipient will receive fees on. - constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwork) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwork) { } - + /// @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 d63a54f013d..3122b8178af 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -20,11 +20,16 @@ contract SequencerFeeVault is FeeVault, ISemver { string public constant version = "1.5.2"; /// @notice Constructs the SequencerFeeVault contract. - /// @param _currentRecipient Wallet that will receive the fees. - /// @param _currentMinWithdrawAmount Minimum balance for withdrawals. - /// @param _currentWithdrawNetwork Network which the recipient will receive fees on. - constructor(address _currentRecipient, uint256 _currentMinWithdrawAmount, Types.WithdrawalNetwork _currentWithdrawNetwork) FeeVault(_currentRecipient, _currentMinWithdrawAmount, _currentWithdrawNetwork) { } - + /// @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. From 999c8ea1a13caba7773277a1c01d741c935340a9 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:58:47 -0500 Subject: [PATCH 14/23] feat: remove proxy admin owned base contract use --- .../contracts-bedrock/src/L2/FeeVault.sol | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 8d5c936429d..282177fe484 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -7,20 +7,20 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; +import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; // Base contracts -import { ProxyAdminOwnedBase } from "src/L1/ProxyAdminOwnedBase.sol"; import { Initializable } from "@openzeppelin/contracts/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 is ProxyAdminOwnedBase, Initializable { - /// @notice Error thrown when the fee splitter is set as the recipient and the withdrawal network is not L2. - error FeeVault_MustHaveL2WithdrawalNetwork(); +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 FeeSplitter_OnlyProxyAdminOwner(); /// @notice Minimum balance before a withdrawal can be triggered. /// Use the `minWithdrawalAmount()` getter as this is deprecated @@ -125,7 +125,6 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { return (_configFlags & uint8(1 << flagPosition)) != 0; } - /// @notice Allow the contract to receive ETH. receive() external payable { } @@ -133,7 +132,9 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { /// withdrawn. /// @param _newMinWithdrawalAmount The new minimum withdrawal amount. function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) external { - _assertOnlyProxyAdminOwner(); + if (msg.sender != IProxyAdmin(Predeploys.PROXY_ADMIN).owner()) { + revert FeeSplitter_OnlyProxyAdminOwner(); + } uint256 oldWithdrawalAmount = _minWithdrawalAmount; _minWithdrawalAmount = _newMinWithdrawalAmount; @@ -145,10 +146,8 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { /// @notice Updates the recipient of sequencer fees when they are withdrawn from the vault. /// @param _newRecipient The new recipient address. function setRecipient(address _newRecipient) external { - _assertOnlyProxyAdminOwner(); - - if (_newRecipient == Predeploys.FEE_SPLITTER && withdrawalNetwork() != Types.WithdrawalNetwork.L2) { - revert FeeVault_MustHaveL2WithdrawalNetwork(); + if (msg.sender != IProxyAdmin(Predeploys.PROXY_ADMIN).owner()) { + revert FeeSplitter_OnlyProxyAdminOwner(); } address oldRecipient = _recipient; @@ -163,10 +162,8 @@ abstract contract FeeVault is ProxyAdminOwnedBase, Initializable { /// withdraw them to an address on the same chain. /// @param _newWithdrawalNetwork The new withdrawal network. function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external { - _assertOnlyProxyAdminOwner(); - - if (recipient() == Predeploys.FEE_SPLITTER && _newWithdrawalNetwork == Types.WithdrawalNetwork.L1) { - revert FeeVault_MustHaveL2WithdrawalNetwork(); + if (msg.sender != IProxyAdmin(Predeploys.PROXY_ADMIN).owner()) { + revert FeeSplitter_OnlyProxyAdminOwner(); } Types.WithdrawalNetwork oldWithdrawalNetwork = _withdrawalNetwork; From 957820293df56884a52755bc73bbba2f010e2f0a Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:59:28 -0500 Subject: [PATCH 15/23] feat: simplify with internal function and singular event --- .../src/L2/FeeVaultInitializer.sol | 214 +++++------------- 1 file changed, 56 insertions(+), 158 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index e79d10062ba..9fa4a07d675 100644 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { FeeVault } from "src/L2/FeeVault.sol"; import { BaseFeeVault } from "src/L2/BaseFeeVault.sol"; import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol"; import { L1FeeVault } from "src/L2/L1FeeVault.sol"; @@ -14,64 +13,26 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; import { IProxy } from "interfaces/universal/IProxy.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 the Base Fee Vault is deployed. - /// @param oldImplementation The previous implementation address. - /// @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 BaseFeeVaultDeployed( - address indexed oldImplementation, - address indexed newImplementation, - address recipient, - Types.WithdrawalNetwork network, - uint256 minWithdrawalAmount - ); - - /// @notice Emitted when the Sequencer Fee Vault is deployed. + /// @notice Emitted when a fee vault implementation is deployed. + /// @param vaultType The type of fee vault being deployed. /// @param oldImplementation The previous implementation address. /// @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 SequencerFeeVaultDeployed( - address indexed oldImplementation, - address indexed newImplementation, - address recipient, - Types.WithdrawalNetwork network, - uint256 minWithdrawalAmount - ); - - /// @notice Emitted when the L1 Fee Vault is deployed. - /// @param oldImplementation The previous implementation address. - /// @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 L1FeeVaultDeployed( - address indexed oldImplementation, - address indexed newImplementation, - address recipient, - Types.WithdrawalNetwork network, - uint256 minWithdrawalAmount - ); - - /// @notice Emitted when the Operator Fee Vault is deployed. - /// @param oldImplementation The previous implementation address. - /// @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 OperatorFeeVaultDeployed( + event FeeVaultDeployed( + string indexed vaultType, address indexed oldImplementation, address indexed newImplementation, address recipient, @@ -87,39 +48,39 @@ contract FeeVaultInitializer is ISemver { _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. + /// @return currentImplementation_ The current implementation address. + function _getFeeVaultConfig(address _feeVaultAddress) + internal + returns (address recipient_, Types.WithdrawalNetwork network_, uint256 minWithdrawalAmount_, address currentImplementation_) + { + currentImplementation_ = IProxy(payable(_feeVaultAddress)).implementation(); + + // 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 { - // Get current values from the existing fee vault - address recipient; - Types.WithdrawalNetwork network; - uint256 minWithdrawalAmount; - address currentImplementation = IProxy(payable(Predeploys.BASE_FEE_VAULT)).implementation(); - - // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails - try FeeVault(payable(Predeploys.BASE_FEE_VAULT)).recipient() returns (address _recipient) { - recipient = _recipient; - } catch { - // Legacy implementation - try snake_case function - recipient = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).RECIPIENT(); - } - - try FeeVault(payable(Predeploys.BASE_FEE_VAULT)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { - network = _network; - } catch { - // Legacy implementation - try snake_case function - network = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).WITHDRAWAL_NETWORK(); - } - - try FeeVault(payable(Predeploys.BASE_FEE_VAULT)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { - minWithdrawalAmount = _minWithdrawalAmount; - } catch { - // Legacy implementation - try snake_case function - minWithdrawalAmount = FeeVault(payable(Predeploys.BASE_FEE_VAULT)).MIN_WITHDRAWAL_AMOUNT(); - } + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount, address currentImplementation) = + _getFeeVaultConfig(Predeploys.BASE_FEE_VAULT); // Deploy new implementation with current values as immutables BaseFeeVault newBaseFeeVault = new BaseFeeVault(recipient, minWithdrawalAmount, network); - emit BaseFeeVaultDeployed( + emit FeeVaultDeployed( + "BaseFeeVault", currentImplementation, address(newBaseFeeVault), recipient, @@ -128,39 +89,18 @@ contract FeeVaultInitializer is ISemver { ); } + /// @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 { - // Get current values from the existing fee vault - address recipient; - Types.WithdrawalNetwork network; - uint256 minWithdrawalAmount; - address currentImplementation = IProxy(payable(Predeploys.SEQUENCER_FEE_WALLET)).implementation(); - - // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails - try FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).recipient() returns (address _recipient) { - recipient = _recipient; - } catch { - // Legacy implementation - try snake_case function - recipient = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).RECIPIENT(); - } - - try FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { - network = _network; - } catch { - // Legacy implementation - try snake_case function - network = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).WITHDRAWAL_NETWORK(); - } - - try FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { - minWithdrawalAmount = _minWithdrawalAmount; - } catch { - // Legacy implementation - try snake_case function - minWithdrawalAmount = FeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).MIN_WITHDRAWAL_AMOUNT(); - } + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount, address currentImplementation) = + _getFeeVaultConfig(Predeploys.SEQUENCER_FEE_WALLET); // Deploy new implementation with current values as immutables SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(recipient, minWithdrawalAmount, network); - emit SequencerFeeVaultDeployed( + emit FeeVaultDeployed( + "SequencerFeeVault", currentImplementation, address(newSequencerFeeVault), recipient, @@ -169,39 +109,18 @@ contract FeeVaultInitializer is ISemver { ); } + /// @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 { - // Get current values from the existing fee vault - address recipient; - Types.WithdrawalNetwork network; - uint256 minWithdrawalAmount; - address currentImplementation = IProxy(payable(Predeploys.L1_FEE_VAULT)).implementation(); - - // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails - try FeeVault(payable(Predeploys.L1_FEE_VAULT)).recipient() returns (address _recipient) { - recipient = _recipient; - } catch { - // Legacy implementation - try snake_case function - recipient = FeeVault(payable(Predeploys.L1_FEE_VAULT)).RECIPIENT(); - } - - try FeeVault(payable(Predeploys.L1_FEE_VAULT)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { - network = _network; - } catch { - // Legacy implementation - try snake_case function - network = FeeVault(payable(Predeploys.L1_FEE_VAULT)).WITHDRAWAL_NETWORK(); - } - - try FeeVault(payable(Predeploys.L1_FEE_VAULT)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { - minWithdrawalAmount = _minWithdrawalAmount; - } catch { - // Legacy implementation - try snake_case function - minWithdrawalAmount = FeeVault(payable(Predeploys.L1_FEE_VAULT)).MIN_WITHDRAWAL_AMOUNT(); - } + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount, address currentImplementation) = + _getFeeVaultConfig(Predeploys.L1_FEE_VAULT); // Deploy new implementation with current values as immutables L1FeeVault newL1FeeVault = new L1FeeVault(recipient, minWithdrawalAmount, network); - emit L1FeeVaultDeployed( + emit FeeVaultDeployed( + "L1FeeVault", currentImplementation, address(newL1FeeVault), recipient, @@ -210,39 +129,18 @@ contract FeeVaultInitializer is ISemver { ); } + /// @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 { - // Get current values from the existing fee vault - address recipient; - Types.WithdrawalNetwork network; - uint256 minWithdrawalAmount; - address currentImplementation = IProxy(payable(Predeploys.OPERATOR_FEE_VAULT)).implementation(); - - // Try to get values using new camelCase functions, fallback to legacy snake_case if it fails - try FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).recipient() returns (address _recipient) { - recipient = _recipient; - } catch { - // Legacy implementation - try snake_case function - recipient = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).RECIPIENT(); - } - - try FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).withdrawalNetwork() returns (Types.WithdrawalNetwork _network) { - network = _network; - } catch { - // Legacy implementation - try snake_case function - network = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).WITHDRAWAL_NETWORK(); - } - - try FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).minWithdrawalAmount() returns (uint256 _minWithdrawalAmount) { - minWithdrawalAmount = _minWithdrawalAmount; - } catch { - // Legacy implementation - try snake_case function - minWithdrawalAmount = FeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).MIN_WITHDRAWAL_AMOUNT(); - } + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount, address currentImplementation) = + _getFeeVaultConfig(Predeploys.OPERATOR_FEE_VAULT); // Deploy new implementation with current values as immutables OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(recipient, minWithdrawalAmount, network); - emit OperatorFeeVaultDeployed( + emit FeeVaultDeployed( + "OperatorFeeVault", currentImplementation, address(newOperatorFeeVault), recipient, From c8923912d8b9bb89da09d624ad8006a1ff1dc1a8 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:47:09 -0500 Subject: [PATCH 16/23] fix: bump versions --- packages/contracts-bedrock/src/L2/BaseFeeVault.sol | 4 ++-- packages/contracts-bedrock/src/L2/L1FeeVault.sol | 4 ++-- packages/contracts-bedrock/src/L2/OperatorFeeVault.sol | 4 ++-- packages/contracts-bedrock/src/L2/SequencerFeeVault.sol | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index 84983c8c3b3..21c171e5fd6 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -16,8 +16,8 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The BaseFeeVault accumulates the base fee that is paid by transactions. contract BaseFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.5.2 - string public constant version = "1.5.2"; + /// @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. diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index a53eaf712c0..58a37ea4e30 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -16,8 +16,8 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The L1FeeVault accumulates the L1 portion of the transaction fees. contract L1FeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.5.2 - string public constant version = "1.5.2"; + /// @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. diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol index 7ef0b0164f2..235de07762b 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -17,8 +17,8 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The OperatorFeeVault accumulates the operator portion of the transaction fees. contract OperatorFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.0.1 - string public constant version = "1.0.1"; + /// @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. diff --git a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol index 3122b8178af..cef66410156 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -16,8 +16,8 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// @notice The SequencerFeeVault is the contract that holds any fees paid to the Sequencer during /// transaction processing and block production. contract SequencerFeeVault is FeeVault, ISemver { - /// @custom:semver 1.5.2 - string public constant version = "1.5.2"; + /// @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. From c2559e28aa788fb6bbc8126cc6c187e1f00c476a Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:50:39 -0500 Subject: [PATCH 17/23] fix: remove initializer --- packages/contracts-bedrock/src/L2/FeeVault.sol | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 282177fe484..1d9335c9c01 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -12,13 +12,11 @@ import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; -// Base contracts -import { Initializable } from "@openzeppelin/contracts/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 is Initializable { +abstract contract FeeVault { /// @notice Error thrown when a function meant to be called by the ProxyAdmin owner is called by another account. error FeeSplitter_OnlyProxyAdminOwner(); @@ -106,7 +104,6 @@ abstract contract FeeVault is Initializable { uint256 _currentMinWithdrawalAmount, Types.WithdrawalNetwork _currentWithdrawalNetwork ) { - _disableInitializers(); RECIPIENT = _currentRecipient; MIN_WITHDRAWAL_AMOUNT = _currentMinWithdrawalAmount; WITHDRAWAL_NETWORK = _currentWithdrawalNetwork; From 951c2a784cc3857732392b9582bf1b1036f5df01 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:53:12 -0500 Subject: [PATCH 18/23] fix: revert to old constructor --- packages/contracts-bedrock/src/L2/FeeVault.sol | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 1d9335c9c01..0e2b73872b7 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -96,17 +96,13 @@ abstract contract FeeVault { Types.WithdrawalNetwork oldWithdrawalNetwork, Types.WithdrawalNetwork newWithdrawalNetwork ); - /// @param _currentRecipient Wallet that will receive the fees. - /// @param _currentMinWithdrawalAmount Minimum balance for withdrawals. - /// @param _currentWithdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _currentRecipient, - uint256 _currentMinWithdrawalAmount, - Types.WithdrawalNetwork _currentWithdrawalNetwork - ) { - RECIPIENT = _currentRecipient; - MIN_WITHDRAWAL_AMOUNT = _currentMinWithdrawalAmount; - WITHDRAWAL_NETWORK = _currentWithdrawalNetwork; + /// @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 Sets a configuration flag to indicate a value has been set by the owner. From 788538b76d81da38a4eba3d94add872a066dccc7 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:56:53 -0500 Subject: [PATCH 19/23] fix: remove current implementation from event and return value --- .../src/L2/FeeVaultInitializer.sol | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index 9fa4a07d675..622987cda38 100644 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -26,14 +26,12 @@ contract FeeVaultInitializer is ISemver { /// @notice Emitted when a fee vault implementation is deployed. /// @param vaultType The type of fee vault being deployed. - /// @param oldImplementation The previous implementation address. /// @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 oldImplementation, address indexed newImplementation, address recipient, Types.WithdrawalNetwork network, @@ -53,13 +51,11 @@ contract FeeVaultInitializer is ISemver { /// @return recipient_ The recipient address. /// @return network_ The withdrawal network. /// @return minWithdrawalAmount_ The minimum withdrawal amount. - /// @return currentImplementation_ The current implementation address. function _getFeeVaultConfig(address _feeVaultAddress) internal - returns (address recipient_, Types.WithdrawalNetwork network_, uint256 minWithdrawalAmount_, address currentImplementation_) + view + returns (address recipient_, Types.WithdrawalNetwork network_, uint256 minWithdrawalAmount_) { - currentImplementation_ = IProxy(payable(_feeVaultAddress)).implementation(); - // Make sure to use legacy functions to avoid failure on upgrade. recipient_ = IFeeVault(payable(_feeVaultAddress)).RECIPIENT(); minWithdrawalAmount_ = IFeeVault(payable(_feeVaultAddress)).MIN_WITHDRAWAL_AMOUNT(); @@ -73,7 +69,7 @@ contract FeeVaultInitializer is ISemver { /// 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, address currentImplementation) = + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = _getFeeVaultConfig(Predeploys.BASE_FEE_VAULT); // Deploy new implementation with current values as immutables @@ -81,7 +77,6 @@ contract FeeVaultInitializer is ISemver { emit FeeVaultDeployed( "BaseFeeVault", - currentImplementation, address(newBaseFeeVault), recipient, network, @@ -93,7 +88,7 @@ contract FeeVaultInitializer is ISemver { /// 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, address currentImplementation) = + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = _getFeeVaultConfig(Predeploys.SEQUENCER_FEE_WALLET); // Deploy new implementation with current values as immutables @@ -101,7 +96,6 @@ contract FeeVaultInitializer is ISemver { emit FeeVaultDeployed( "SequencerFeeVault", - currentImplementation, address(newSequencerFeeVault), recipient, network, @@ -113,7 +107,7 @@ contract FeeVaultInitializer is ISemver { /// 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, address currentImplementation) = + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = _getFeeVaultConfig(Predeploys.L1_FEE_VAULT); // Deploy new implementation with current values as immutables @@ -121,7 +115,6 @@ contract FeeVaultInitializer is ISemver { emit FeeVaultDeployed( "L1FeeVault", - currentImplementation, address(newL1FeeVault), recipient, network, @@ -133,7 +126,7 @@ contract FeeVaultInitializer is ISemver { /// 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, address currentImplementation) = + (address recipient, Types.WithdrawalNetwork network, uint256 minWithdrawalAmount) = _getFeeVaultConfig(Predeploys.OPERATOR_FEE_VAULT); // Deploy new implementation with current values as immutables @@ -141,7 +134,6 @@ contract FeeVaultInitializer is ISemver { emit FeeVaultDeployed( "OperatorFeeVault", - currentImplementation, address(newOperatorFeeVault), recipient, network, From ea62e5b73fc344d25731cfdebd1b9f5eb49a4cae Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:10:02 -0500 Subject: [PATCH 20/23] chore: remove unused imports --- packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol | 1 - packages/contracts-bedrock/src/L2/OperatorFeeVault.sol | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index 622987cda38..11b72b92e37 100644 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -12,7 +12,6 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; -import { IProxy } from "interfaces/universal/IProxy.sol"; import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; /// @title FeeVaultInitializer diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol index 235de07762b..c888890d2ea 100644 --- a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -6,7 +6,6 @@ import { FeeVault } from "src/L2/FeeVault.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; -import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; From c556429ff421283a0d857e993859ecab41ec8440 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 15:01:26 -0500 Subject: [PATCH 21/23] fix: gap of 44 --- packages/contracts-bedrock/src/L2/FeeVault.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 0e2b73872b7..6c36d045954 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -12,7 +12,6 @@ import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; // Libraries import { Types } from "src/libraries/Types.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. @@ -63,7 +62,7 @@ abstract contract FeeVault { uint8 private _configFlags; /// @notice Reserve extra slots in the storage layout for future upgrades, 50 in total. - uint256[43] private __gap; + uint256[44] private __gap; /// @notice Emitted each time a withdrawal occurs. This event will be deprecated /// in favor of the Withdrawal event containing the WithdrawalNetwork parameter. From ac51ebd11b0c5590f39e2b7c392df721a5ed917a Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Wed, 27 Aug 2025 15:01:58 -0500 Subject: [PATCH 22/23] chore: pre pr checks --- .../interfaces/L2/IFeeVault.sol | 14 +- .../interfaces/L2/IFeeVaultInitializer.sol | 22 + .../contracts-bedrock/scripts/L2Genesis.s.sol | 6 +- .../snapshots/abi/BaseFeeVault.json | 107 ++++- .../snapshots/abi/FeeSplitter.json | 388 +++--------------- .../snapshots/abi/FeeVaultInitializer.json | 57 +++ .../snapshots/abi/L1FeeVault.json | 107 ++++- .../snapshots/abi/OperatorFeeVault.json | 125 +++++- .../snapshots/abi/SequencerFeeVault.json | 107 ++++- .../abi/SuperchainRevSharesCalculator.json | 231 +++++++++++ .../snapshots/semver-lock.json | 28 +- .../snapshots/storageLayout/BaseFeeVault.json | 34 +- .../snapshots/storageLayout/FeeSplitter.json | 59 +-- .../storageLayout/FeeVaultInitializer.json | 1 + .../snapshots/storageLayout/L1FeeVault.json | 34 +- .../storageLayout/OperatorFeeVault.json | 34 +- .../storageLayout/SequencerFeeVault.json | 34 +- .../SuperchainRevSharesCalculator.json | 30 ++ .../contracts-bedrock/src/L2/FeeSplitter.sol | 14 +- .../src/L2/FeeVaultInitializer.sol | 33 +- .../src/L2/SuperchainRevSharesCalculator.sol | 14 +- .../test/L2/FeeSplitter.t.sol | 94 +++-- 22 files changed, 1067 insertions(+), 506 deletions(-) create mode 100644 packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol create mode 100644 packages/contracts-bedrock/snapshots/abi/FeeVaultInitializer.json create mode 100644 packages/contracts-bedrock/snapshots/abi/SuperchainRevSharesCalculator.json create mode 100644 packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json create mode 100644 packages/contracts-bedrock/snapshots/storageLayout/SuperchainRevSharesCalculator.json diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol b/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol index 2afe02f90d6..4514225beb4 100644 --- a/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol +++ b/packages/contracts-bedrock/interfaces/L2/IFeeVault.sol @@ -4,19 +4,27 @@ pragma solidity ^0.8.0; import { Types } from "src/libraries/Types.sol"; interface IFeeVault { + error FeeSplitter_OnlyProxyAdminOwner(); + 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); + event RecipientUpdated(address oldRecipient, address newRecipient); + event WithdrawalNetworkUpdated(Types.WithdrawalNetwork oldWithdrawalNetwork, Types.WithdrawalNetwork newWithdrawalNetwork); receive() external payable; function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); - function minWithdrawalAmount() external view returns (uint256 amount_); - function recipient() external view returns (address recipient_); + function minWithdrawalAmount() external view returns (uint256); + function recipient() external view returns (address); function totalProcessed() external view returns (uint256); function withdraw() external; - function withdrawalNetwork() external view returns (Types.WithdrawalNetwork network_); + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork); + function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) external; + function setRecipient(address _newRecipient) external; + function setWithdrawalNetwork(Types.WithdrawalNetwork _newWithdrawalNetwork) external; function __constructor__() external; } diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol b/packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol new file mode 100644 index 00000000000..da5d6debe84 --- /dev/null +++ b/packages/contracts-bedrock/interfaces/L2/IFeeVaultInitializer.sol @@ -0,0 +1,22 @@ +// 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/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index eaae9ddbbf6..f2fd2b017b9 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -582,14 +582,12 @@ contract L2Genesis is Script { vm.startPrank(_input.opChainProxyAdminOwner); // Initialize the implementation with address(0) for addresses IFeeSplitter(payable(impl)).initialize( - ISharesCalculator(address(0)), - uint128(_input.feeSplitterFeeDisbursementInterval) + ISharesCalculator(address(0)), uint128(_input.feeSplitterFeeDisbursementInterval) ); // Initialize the proxy with the actual values IFeeSplitter(payable(Predeploys.FEE_SPLITTER)).initialize( - ISharesCalculator(_input.feeSplitterSharesCalculator), - uint128(_input.feeSplitterFeeDisbursementInterval) + ISharesCalculator(_input.feeSplitterSharesCalculator), uint128(_input.feeSplitterFeeDisbursementInterval) ); vm.stopPrank(); } diff --git a/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json b/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json index b745bcb8184..2b4121958e1 100644 --- a/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json @@ -69,7 +69,7 @@ "outputs": [ { "internalType": "uint256", - "name": "amount_", + "name": "", "type": "uint256" } ], @@ -82,13 +82,52 @@ "outputs": [ { "internalType": "address", - "name": "recipient_", + "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newMinWithdrawalAmount", + "type": "uint256" + } + ], + "name": "setMinWithdrawalAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newRecipient", + "type": "address" + } + ], + "name": "setRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "setWithdrawalNetwork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "totalProcessed", @@ -128,13 +167,51 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWithdrawalAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWithdrawalAmount", + "type": "uint256" + } + ], + "name": "MinWithdrawalAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldRecipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newRecipient", + "type": "address" + } + ], + "name": "RecipientUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -190,5 +267,29 @@ ], "name": "Withdrawal", "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "oldWithdrawalNetwork", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "WithdrawalNetworkUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "FeeSplitter_OnlyProxyAdminOwner", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json b/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json index 5f5f234015f..565fb208fe4 100644 --- a/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json +++ b/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json @@ -8,58 +8,6 @@ "stateMutability": "payable", "type": "receive" }, - { - "inputs": [], - "name": "BASIS_POINT_SCALE", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MIN_FEE_DISBURSEMENT_INTERVAL", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "_PAYOUT_CLOSED", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "_PAYOUT_OPEN", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "disburseFees", @@ -72,22 +20,9 @@ "name": "feeDisbursementInterval", "outputs": [ { - "internalType": "uint40", + "internalType": "uint128", "name": "", - "type": "uint40" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "grossFeeShareBP", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" + "type": "uint128" } ], "stateMutability": "view", @@ -96,29 +31,14 @@ { "inputs": [ { - "internalType": "address payable", - "name": "_revenueShareRecipient", + "internalType": "contract ISharesCalculator", + "name": "_shareCalculator", "type": "address" }, { - "internalType": "address payable", - "name": "_revenueRemainderRecipient", - "type": "address" - }, - { - "internalType": "uint40", + "internalType": "uint128", "name": "_feeDisbursementInterval", - "type": "uint40" - }, - { - "internalType": "uint16", - "name": "_netFeeShareBP", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "_grossFeeShareBP", - "type": "uint16" + "type": "uint128" } ], "name": "initialize", @@ -131,74 +51,9 @@ "name": "lastDisbursementTime", "outputs": [ { - "internalType": "uint40", - "name": "", - "type": "uint40" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "netFeeRevenue", - "outputs": [ - { - "internalType": "uint144", - "name": "", - "type": "uint144" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "netFeeShareBP", - "outputs": [ - { - "internalType": "uint16", + "internalType": "uint128", "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "payoutGateState", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "revenueRemainderRecipient", - "outputs": [ - { - "internalType": "address payable", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "revenueShareRecipient", - "outputs": [ - { - "internalType": "address payable", - "name": "", - "type": "address" + "type": "uint128" } ], "stateMutability": "view", @@ -207,9 +62,9 @@ { "inputs": [ { - "internalType": "uint40", + "internalType": "uint128", "name": "_newFeeDisbursementInterval", - "type": "uint40" + "type": "uint128" } ], "name": "setFeeDisbursementInterval", @@ -220,53 +75,27 @@ { "inputs": [ { - "internalType": "uint16", - "name": "_newGrossFeeShareBP", - "type": "uint16" - } - ], - "name": "setGrossFeeShareBP", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_newNetFeeShareBP", - "type": "uint16" - } - ], - "name": "setNetFeeShareBP", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "_newRevenueRemainderRecipient", + "internalType": "contract ISharesCalculator", + "name": "_newShareCalculator", "type": "address" } ], - "name": "setRevenueRemainderRecipient", + "name": "setShareCalculator", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "shareCalculator", + "outputs": [ { - "internalType": "address", - "name": "_newRevenueShareRecipient", + "internalType": "contract ISharesCalculator", + "name": "", "type": "address" } ], - "name": "setRevenueShareRecipient", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -287,15 +116,15 @@ "inputs": [ { "indexed": false, - "internalType": "uint40", + "internalType": "uint128", "name": "oldFeeDisbursementInterval", - "type": "uint40" + "type": "uint128" }, { "indexed": false, - "internalType": "uint40", + "internalType": "uint128", "name": "newFeeDisbursementInterval", - "type": "uint40" + "type": "uint128" } ], "name": "FeeDisbursementIntervalUpdated", @@ -305,27 +134,27 @@ "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "uint256", - "name": "disbursementTime", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "revenueShareRecipientAmount", - "type": "uint256" - }, - { + "components": [ + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], "indexed": false, - "internalType": "uint256", - "name": "revenueRemainderRecipientAmount", - "type": "uint256" + "internalType": "struct ShareInfo[]", + "name": "shareInfo", + "type": "tuple[]" }, { "indexed": false, "internalType": "uint256", - "name": "totalFeesDisbursed", + "name": "grossRevenue", "type": "uint256" } ], @@ -351,62 +180,6 @@ "name": "FeesReceived", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint16", - "name": "oldGrossFeeShareBP", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "newGrossFeeShareBP", - "type": "uint16" - } - ], - "name": "GrossFeeShareBPUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address payable", - "name": "revenueShareRecipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "address payable", - "name": "revenueRemainderRecipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint40", - "name": "feeDisbursementInterval", - "type": "uint40" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "netFeeShareBP", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "grossFeeShareBP", - "type": "uint16" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -425,62 +198,37 @@ "inputs": [ { "indexed": false, - "internalType": "uint16", - "name": "oldNetFeeShareBP", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "newNetFeeShareBP", - "type": "uint16" - } - ], - "name": "NetFeeShareBPUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "NoFeesCollected", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldRevenueRemainderRecipient", + "internalType": "contract ISharesCalculator", + "name": "shareCalculator", "type": "address" }, { - "indexed": true, - "internalType": "address", - "name": "newRevenueRemainderRecipient", - "type": "address" + "indexed": false, + "internalType": "uint128", + "name": "feeDisbursementInterval", + "type": "uint128" } ], - "name": "RevenueRemainderRecipientUpdated", + "name": "Initialized", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, + "indexed": false, "internalType": "address", - "name": "oldRevenueShareRecipient", + "name": "oldShareCalculator", "type": "address" }, { - "indexed": true, + "indexed": false, "internalType": "address", - "name": "newRevenueShareRecipient", + "name": "newShareCalculator", "type": "address" } ], - "name": "RevenueShareRecipientUpdated", + "name": "ShareCalculatorUpdated", "type": "event" }, { @@ -488,11 +236,6 @@ "name": "FeeSplitter_DisbursementIntervalNotReached", "type": "error" }, - { - "inputs": [], - "name": "FeeSplitter_FailedToSendToRevenueRemainderRecipient", - "type": "error" - }, { "inputs": [], "name": "FeeSplitter_FailedToSendToRevenueShareRecipient", @@ -500,12 +243,7 @@ }, { "inputs": [], - "name": "FeeSplitter_FeeDisbursementIntervalTooShort", - "type": "error" - }, - { - "inputs": [], - "name": "FeeSplitter_FeeShareBPExceeds100Percent", + "name": "FeeSplitter_FeeShareInfoEmpty", "type": "error" }, { @@ -520,42 +258,32 @@ }, { "inputs": [], - "name": "FeeSplitter_GrossFeeShareBPExceeds100Percent", - "type": "error" - }, - { - "inputs": [], - "name": "FeeSplitter_NewFeeDisbursementIntervalTooShort", + "name": "FeeSplitter_NoFeesCollected", "type": "error" }, { "inputs": [], - "name": "FeeSplitter_NewRevenueRemainderRecipientCannotBeZero", - "type": "error" - }, - { - "inputs": [], - "name": "FeeSplitter_NewRevenueShareRecipientCannotBeZero", + "name": "FeeSplitter_OnlyProxyAdminOwner", "type": "error" }, { "inputs": [], - "name": "FeeSplitter_OnlyProxyAdminOwner", + "name": "FeeSplitter_ReceiveWindowClosed", "type": "error" }, { "inputs": [], - "name": "FeeSplitter_ReceiveDisabledDuringPayout", + "name": "FeeSplitter_SenderNotApprovedVault", "type": "error" }, { "inputs": [], - "name": "FeeSplitter_RevenueRemainderRecipientCannotBeZero", + "name": "FeeSplitter_ShareCalculatorCannotBeZero", "type": "error" }, { "inputs": [], - "name": "FeeSplitter_RevenueShareRecipientCannotBeZero", + "name": "FeeSplitter_ShareCalculatorMalformedOutput", "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 new file mode 100644 index 00000000000..87b58357d78 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/FeeVaultInitializer.json @@ -0,0 +1,57 @@ +[ + { + "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 b745bcb8184..2b4121958e1 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json @@ -69,7 +69,7 @@ "outputs": [ { "internalType": "uint256", - "name": "amount_", + "name": "", "type": "uint256" } ], @@ -82,13 +82,52 @@ "outputs": [ { "internalType": "address", - "name": "recipient_", + "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newMinWithdrawalAmount", + "type": "uint256" + } + ], + "name": "setMinWithdrawalAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newRecipient", + "type": "address" + } + ], + "name": "setRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "setWithdrawalNetwork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "totalProcessed", @@ -128,13 +167,51 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWithdrawalAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWithdrawalAmount", + "type": "uint256" + } + ], + "name": "MinWithdrawalAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldRecipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newRecipient", + "type": "address" + } + ], + "name": "RecipientUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -190,5 +267,29 @@ ], "name": "Withdrawal", "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "oldWithdrawalNetwork", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "WithdrawalNetworkUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "FeeSplitter_OnlyProxyAdminOwner", + "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 657c3d27808..2b4121958e1 100644 --- a/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json @@ -1,6 +1,22 @@ [ { - "inputs": [], + "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" }, @@ -53,7 +69,7 @@ "outputs": [ { "internalType": "uint256", - "name": "amount_", + "name": "", "type": "uint256" } ], @@ -66,13 +82,52 @@ "outputs": [ { "internalType": "address", - "name": "recipient_", + "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newMinWithdrawalAmount", + "type": "uint256" + } + ], + "name": "setMinWithdrawalAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newRecipient", + "type": "address" + } + ], + "name": "setRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "setWithdrawalNetwork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "totalProcessed", @@ -112,13 +167,51 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWithdrawalAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWithdrawalAmount", + "type": "uint256" + } + ], + "name": "MinWithdrawalAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldRecipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newRecipient", + "type": "address" + } + ], + "name": "RecipientUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -174,5 +267,29 @@ ], "name": "Withdrawal", "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "oldWithdrawalNetwork", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "WithdrawalNetworkUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "FeeSplitter_OnlyProxyAdminOwner", + "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 700e7d7b981..fd70ca64640 100644 --- a/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json @@ -82,7 +82,7 @@ "outputs": [ { "internalType": "uint256", - "name": "amount_", + "name": "", "type": "uint256" } ], @@ -95,13 +95,52 @@ "outputs": [ { "internalType": "address", - "name": "recipient_", + "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newMinWithdrawalAmount", + "type": "uint256" + } + ], + "name": "setMinWithdrawalAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newRecipient", + "type": "address" + } + ], + "name": "setRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "setWithdrawalNetwork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "totalProcessed", @@ -141,13 +180,51 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWithdrawalAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWithdrawalAmount", + "type": "uint256" + } + ], + "name": "MinWithdrawalAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldRecipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newRecipient", + "type": "address" + } + ], + "name": "RecipientUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -203,5 +280,29 @@ ], "name": "Withdrawal", "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "oldWithdrawalNetwork", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "newWithdrawalNetwork", + "type": "uint8" + } + ], + "name": "WithdrawalNetworkUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "FeeSplitter_OnlyProxyAdminOwner", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/SuperchainRevSharesCalculator.json b/packages/contracts-bedrock/snapshots/abi/SuperchainRevSharesCalculator.json new file mode 100644 index 00000000000..a671b3bbaee --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/SuperchainRevSharesCalculator.json @@ -0,0 +1,231 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "BASIS_POINT_SCALE", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GROSS_SHARE_BPS", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NET_SHARE_BPS", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_sequencerFeeRevenue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_baseFeeRevenue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_operatorFeeRevenue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l1FeeRevenue", + "type": "uint256" + } + ], + "name": "getRecipientsAndValues", + "outputs": [ + { + "components": [ + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "internalType": "struct ShareInfo[]", + "name": "shareInfo", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_shareRecipient", + "type": "address" + }, + { + "internalType": "address payable", + "name": "_remainderRecipient", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "remainderRecipient", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_remainderRecipient", + "type": "address" + } + ], + "name": "setRemainderRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_shareRecipient", + "type": "address" + } + ], + "name": "setShareRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "shareRecipient", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "remainderRecipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "oldRemainderRecipient", + "type": "address" + } + ], + "name": "RemainderRecipientUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "shareRecipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "oldSHareRecipient", + "type": "address" + } + ], + "name": "ShareRecipientUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "SharesCalculator_OnlyProxyAdminOwner", + "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 ee9789f5799..4670b7f79fb 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -44,8 +44,8 @@ "sourceCodeHash": "0x997212ceadabb306c2abd31918b09bccbba0b21662c1d8930a3599831c374b13" }, "src/L2/BaseFeeVault.sol:BaseFeeVault": { - "initCodeHash": "0x9b664e3d84ad510091337b4aacaa494b142512e2f6f7fbcdb6210ed62ca9b885", - "sourceCodeHash": "0x508610081cade08f935e2a66f31cc193874bc0e2971a65db4a7842f1a428b1d0" + "initCodeHash": "0xe68cf9422671396ab876cdae71ddfa634a511b8400fa784f466bec380ce4aa84", + "sourceCodeHash": "0x2e3673e0b592204ef30dc58d44c66d6587c8efe5fb5aeaf1a3a757343d06d09f" }, "src/L2/CrossL2Inbox.sol:CrossL2Inbox": { "initCodeHash": "0x56f868e561c4abe539043f98b16aad9305479e68fd03ece2233249b0c73a24ea", @@ -56,8 +56,12 @@ "sourceCodeHash": "0x6d137fef431d75a8bf818444915fc39c8b1d93434a9af9971d96fb3170bc72b7" }, "src/L2/FeeSplitter.sol:FeeSplitter": { - "initCodeHash": "0x38c00e0b26d664be3e2976bb93ef908fb186e80a0f4432737dd98c7a2061db8c", - "sourceCodeHash": "0x7e1b063c20074c8085d427e031353af72b3cb570c724d203b39f33d52434d7f8" + "initCodeHash": "0x0795a2d9e353f98750997c7475be9bac693105d2f361c669a10b0fd5826c0efb", + "sourceCodeHash": "0xe2f567d995f6abecfb92a64a57894caabfdfa81c803e555cce1e2ab2e7713e83" + }, + "src/L2/FeeVaultInitializer.sol:FeeVaultInitializer": { + "initCodeHash": "0x453a28d8c3ef30a99ed18163ac7a49e57138545470b5de78c7fdf0ebce2c1b90", + "sourceCodeHash": "0x51cc656fde167195e8d142d3e95f957f3bbcf2782bbe6b6f975452f009e65d9f" }, "src/L2/GasPriceOracle.sol:GasPriceOracle": { "initCodeHash": "0x38ef70b2783dd45ad807afcf57972c7df4abaaeb5d16d17cdb451b9e931a9cbb", @@ -68,8 +72,8 @@ "sourceCodeHash": "0x6e5349fd781d5f0127ff29ccea4d86a80240550cfa322364183a0f629abcb43e" }, "src/L2/L1FeeVault.sol:L1FeeVault": { - "initCodeHash": "0x9b664e3d84ad510091337b4aacaa494b142512e2f6f7fbcdb6210ed62ca9b885", - "sourceCodeHash": "0xfdf158752a5802c3697d6e8467046f6378680ceaa9e59ab02da0f5dcd575e5e2" + "initCodeHash": "0xe68cf9422671396ab876cdae71ddfa634a511b8400fa784f466bec380ce4aa84", + "sourceCodeHash": "0x2e85139090b9072e368a5ff36e5fcf2a90b219c6024e06a7998904cd75412395" }, "src/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger": { "initCodeHash": "0xe160be403df12709c371c33195d1b9c3b5e9499e902e86bdabc8eed749c3fd61", @@ -96,8 +100,8 @@ "sourceCodeHash": "0xbea4229c5c6988243dbc7cf5a086ddd412fe1f2903b8e20d56699fec8de0c2c9" }, "src/L2/OperatorFeeVault.sol:OperatorFeeVault": { - "initCodeHash": "0x3d8c0d7736e8767f2f797da1c20c5fe30bd7f48a4cf75f376290481ad7c0f91f", - "sourceCodeHash": "0x2022fdb4e32769eb9446dab4aed4b8abb5261fd866f381cccfa7869df1a2adff" + "initCodeHash": "0xf31c45f2c8918bc048bdb72ba2113b449bc9b7b4fcad67475baee1c8f4d8543c", + "sourceCodeHash": "0xcf6f8ca3a9d093c91722fe15489c6a5566f54dd38f14a82e7e063019e4ea507c" }, "src/L2/OptimismMintableERC721.sol:OptimismMintableERC721": { "initCodeHash": "0x316c6d716358f5b5284cd5457ea9fca4b5ad4a37835d4b4b300413dafbfa2159", @@ -120,8 +124,8 @@ "sourceCodeHash": "0x11b6236911e909ed10d4f194fe7315c1f5533d21cbe69a8ff16248c827df2647" }, "src/L2/SequencerFeeVault.sol:SequencerFeeVault": { - "initCodeHash": "0x96474e1d225513c931b8c5c656541212d659686ddc6d49a72ac4df9d640eedd5", - "sourceCodeHash": "0x7df290a6fbc8e712cf4411c3965fd4c59511477f70e666882c57f7c25cf4523e" + "initCodeHash": "0xf75800910406ecf2320664c5d874dd052f7696bae4cbe659443d6d3c10861259", + "sourceCodeHash": "0x755e5296877de76bb659212acae5980775825c7469c7a4d21f8f75bcdb5fbabd" }, "src/L2/SuperchainERC20.sol:SuperchainERC20": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", @@ -131,6 +135,10 @@ "initCodeHash": "0xa43665ad0f2b4f092ff04b12e38f24aa8d2cb34ae7a06fc037970743547bdf98", "sourceCodeHash": "0x862b8a2e5dd5cafcda55e35df7713b0d0b7a93d4d6ce29ea9ca53e045bf63cb4" }, + "src/L2/SuperchainRevSharesCalculator.sol:SuperchainRevSharesCalculator": { + "initCodeHash": "0x6c280cd93f24b07c4fbf9c84ad0537026390b17cef986cc3d14811c43d76f5c9", + "sourceCodeHash": "0x4090da123ba9484b5016b82236da6e9d5ef258e29eba19beb209e792303206e3" + }, "src/L2/SuperchainTokenBridge.sol:SuperchainTokenBridge": { "initCodeHash": "0xb0d25dc03b9c84b07b263921c2b717e6caad3f4297fa939207e35978d7d25abe", "sourceCodeHash": "0x0ff7c1f0264d784fac5d69b792c6bc9d064d4a09701c1bafa808388685c8c4f1" diff --git a/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json index 93c5a7ec8a6..7342c089512 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/BaseFeeVault.json @@ -7,10 +7,38 @@ "type": "uint256" }, { - "bytes": "1536", - "label": "__gap", + "bytes": "32", + "label": "_minWithdrawalAmount", "offset": 0, "slot": "1", - "type": "uint256[48]" + "type": "uint256" + }, + { + "bytes": "20", + "label": "_recipient", + "offset": 0, + "slot": "2", + "type": "address" + }, + { + "bytes": "1", + "label": "_withdrawalNetwork", + "offset": 20, + "slot": "2", + "type": "enum Types.WithdrawalNetwork" + }, + { + "bytes": "1", + "label": "_configFlags", + "offset": 21, + "slot": "2", + "type": "uint8" + }, + { + "bytes": "1408", + "label": "__gap", + "offset": 0, + "slot": "3", + "type": "uint256[44]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/FeeSplitter.json b/packages/contracts-bedrock/snapshots/storageLayout/FeeSplitter.json index 0419bfc632f..320492f5375 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/FeeSplitter.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/FeeSplitter.json @@ -15,65 +15,30 @@ }, { "bytes": "32", - "label": "_status", + "label": "_revenuePerVault", "offset": 0, "slot": "1", - "type": "uint256" + "type": "mapping(address => uint256)" }, { - "bytes": "32", - "label": "payoutGateState", + "bytes": "20", + "label": "shareCalculator", "offset": 0, "slot": "2", - "type": "uint256" + "type": "contract ISharesCalculator" }, { - "bytes": "20", - "label": "revenueShareRecipient", + "bytes": "16", + "label": "lastDisbursementTime", "offset": 0, "slot": "3", - "type": "address payable" - }, - { - "bytes": "20", - "label": "revenueRemainderRecipient", - "offset": 0, - "slot": "4", - "type": "address payable" + "type": "uint128" }, { - "bytes": "18", - "label": "netFeeRevenue", - "offset": 0, - "slot": "5", - "type": "uint144" - }, - { - "bytes": "5", - "label": "lastDisbursementTime", - "offset": 18, - "slot": "5", - "type": "uint40" - }, - { - "bytes": "2", - "label": "netFeeShareBP", - "offset": 23, - "slot": "5", - "type": "uint16" - }, - { - "bytes": "2", - "label": "grossFeeShareBP", - "offset": 25, - "slot": "5", - "type": "uint16" - }, - { - "bytes": "5", + "bytes": "16", "label": "feeDisbursementInterval", - "offset": 27, - "slot": "5", - "type": "uint40" + "offset": 16, + "slot": "3", + "type": "uint128" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json b/packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/FeeVaultInitializer.json @@ -0,0 +1 @@ +[] \ 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 93c5a7ec8a6..7342c089512 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1FeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1FeeVault.json @@ -7,10 +7,38 @@ "type": "uint256" }, { - "bytes": "1536", - "label": "__gap", + "bytes": "32", + "label": "_minWithdrawalAmount", "offset": 0, "slot": "1", - "type": "uint256[48]" + "type": "uint256" + }, + { + "bytes": "20", + "label": "_recipient", + "offset": 0, + "slot": "2", + "type": "address" + }, + { + "bytes": "1", + "label": "_withdrawalNetwork", + "offset": 20, + "slot": "2", + "type": "enum Types.WithdrawalNetwork" + }, + { + "bytes": "1", + "label": "_configFlags", + "offset": 21, + "slot": "2", + "type": "uint8" + }, + { + "bytes": "1408", + "label": "__gap", + "offset": 0, + "slot": "3", + "type": "uint256[44]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json index 93c5a7ec8a6..7342c089512 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json @@ -7,10 +7,38 @@ "type": "uint256" }, { - "bytes": "1536", - "label": "__gap", + "bytes": "32", + "label": "_minWithdrawalAmount", "offset": 0, "slot": "1", - "type": "uint256[48]" + "type": "uint256" + }, + { + "bytes": "20", + "label": "_recipient", + "offset": 0, + "slot": "2", + "type": "address" + }, + { + "bytes": "1", + "label": "_withdrawalNetwork", + "offset": 20, + "slot": "2", + "type": "enum Types.WithdrawalNetwork" + }, + { + "bytes": "1", + "label": "_configFlags", + "offset": 21, + "slot": "2", + "type": "uint8" + }, + { + "bytes": "1408", + "label": "__gap", + "offset": 0, + "slot": "3", + "type": "uint256[44]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json index 93c5a7ec8a6..7342c089512 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/SequencerFeeVault.json @@ -7,10 +7,38 @@ "type": "uint256" }, { - "bytes": "1536", - "label": "__gap", + "bytes": "32", + "label": "_minWithdrawalAmount", "offset": 0, "slot": "1", - "type": "uint256[48]" + "type": "uint256" + }, + { + "bytes": "20", + "label": "_recipient", + "offset": 0, + "slot": "2", + "type": "address" + }, + { + "bytes": "1", + "label": "_withdrawalNetwork", + "offset": 20, + "slot": "2", + "type": "enum Types.WithdrawalNetwork" + }, + { + "bytes": "1", + "label": "_configFlags", + "offset": 21, + "slot": "2", + "type": "uint8" + }, + { + "bytes": "1408", + "label": "__gap", + "offset": 0, + "slot": "3", + "type": "uint256[44]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/SuperchainRevSharesCalculator.json b/packages/contracts-bedrock/snapshots/storageLayout/SuperchainRevSharesCalculator.json new file mode 100644 index 00000000000..60a2a2bd137 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/SuperchainRevSharesCalculator.json @@ -0,0 +1,30 @@ +[ + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "bool" + }, + { + "bytes": "20", + "label": "shareRecipient", + "offset": 2, + "slot": "0", + "type": "address payable" + }, + { + "bytes": "20", + "label": "remainderRecipient", + "offset": 0, + "slot": "1", + "type": "address payable" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index d1508366fba..9c126c63a6a 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -12,7 +12,6 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; import { ISharesCalculator, ShareInfo } from "interfaces/L2/ISharesCalculator.sol"; import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; - // OpenZeppelin import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; @@ -57,7 +56,8 @@ contract FeeSplitter is ISemver, Initializable { /// @notice Transient storage slot key for disbursement-in-progress flag. /// Equal to bytes32(uint256(keccak256("feesplitter.isDisbursing")) - 1) - bytes32 internal constant _FEE_SPLITTER_IS_DISBURSING_SLOT = 0xe3007e9730850b5618eacb0537bef0cf0f1600267ae8549e472449d77b731e45; + bytes32 internal constant _FEE_SPLITTER_IS_DISBURSING_SLOT = + 0xe3007e9730850b5618eacb0537bef0cf0f1600267ae8549e472449d77b731e45; /// @notice Tracks the revenue received by each vault. mapping(address => uint256) internal _revenuePerVault; @@ -107,13 +107,7 @@ contract FeeSplitter is ISemver, Initializable { /// @dev This function can only be called once and must be called by the ProxyAdmin owner. /// @param _shareCalculator The share calculator contract. /// @param _feeDisbursementInterval The minimum amount of time in seconds that must pass between fee disbursals. - function initialize( - ISharesCalculator _shareCalculator, - uint128 _feeDisbursementInterval - ) - external - initializer - { + function initialize(ISharesCalculator _shareCalculator, uint128 _feeDisbursementInterval) external initializer { shareCalculator = _shareCalculator; feeDisbursementInterval = _feeDisbursementInterval; @@ -252,4 +246,4 @@ contract FeeSplitter is ISemver, Initializable { isDisbursing_ := tload(_FEE_SPLITTER_IS_DISBURSING_SLOT) } } -} \ No newline at end of file +} diff --git a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol index 11b72b92e37..c9f131cf5d5 100644 --- a/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol +++ b/packages/contracts-bedrock/src/L2/FeeVaultInitializer.sol @@ -59,7 +59,8 @@ contract FeeVaultInitializer is ISemver { 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, ())); + (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; } @@ -74,13 +75,7 @@ contract FeeVaultInitializer is ISemver { // Deploy new implementation with current values as immutables BaseFeeVault newBaseFeeVault = new BaseFeeVault(recipient, minWithdrawalAmount, network); - emit FeeVaultDeployed( - "BaseFeeVault", - address(newBaseFeeVault), - recipient, - network, - minWithdrawalAmount - ); + emit FeeVaultDeployed("BaseFeeVault", address(newBaseFeeVault), recipient, network, minWithdrawalAmount); } /// @notice Deploys a new Sequencer Fee Vault implementation with current configuration as immutables. @@ -94,11 +89,7 @@ contract FeeVaultInitializer is ISemver { SequencerFeeVault newSequencerFeeVault = new SequencerFeeVault(recipient, minWithdrawalAmount, network); emit FeeVaultDeployed( - "SequencerFeeVault", - address(newSequencerFeeVault), - recipient, - network, - minWithdrawalAmount + "SequencerFeeVault", address(newSequencerFeeVault), recipient, network, minWithdrawalAmount ); } @@ -112,13 +103,7 @@ contract FeeVaultInitializer is ISemver { // Deploy new implementation with current values as immutables L1FeeVault newL1FeeVault = new L1FeeVault(recipient, minWithdrawalAmount, network); - emit FeeVaultDeployed( - "L1FeeVault", - address(newL1FeeVault), - recipient, - network, - minWithdrawalAmount - ); + emit FeeVaultDeployed("L1FeeVault", address(newL1FeeVault), recipient, network, minWithdrawalAmount); } /// @notice Deploys a new Operator Fee Vault implementation with current configuration as immutables. @@ -131,12 +116,6 @@ contract FeeVaultInitializer is ISemver { // Deploy new implementation with current values as immutables OperatorFeeVault newOperatorFeeVault = new OperatorFeeVault(recipient, minWithdrawalAmount, network); - emit FeeVaultDeployed( - "OperatorFeeVault", - address(newOperatorFeeVault), - recipient, - network, - minWithdrawalAmount - ); + emit FeeVaultDeployed("OperatorFeeVault", address(newOperatorFeeVault), recipient, network, minWithdrawalAmount); } } diff --git a/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol b/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol index 221373802a0..1ac73cc2005 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol @@ -14,8 +14,8 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I /// @custom:proxied /// @title SuperchainRevSharesCalculator -/// @notice Calculator for Superchain revenue share. It pays the greater amount between 2.5% of -/// gross revenue or 15% of net revenue (gross minus L1 fees) to the configured share recipient. +/// @notice Calculator for Superchain revenue share. It pays the greater amount between 2.5% of +/// gross revenue or 15% of net revenue (gross minus L1 fees) to the configured share recipient. /// The second configured recipient receives the full remainder via FeeSplitter's remainder send. contract SuperchainRevSharesCalculator is ISemver, Initializable { /// @notice Emitted when the share recipient is updated. @@ -56,13 +56,7 @@ contract SuperchainRevSharesCalculator is ISemver, Initializable { /// @notice Initializes the contract with an initial configuration. /// @param _shareRecipient Recipient of the Superchain revenue share. /// @param _remainderRecipient Recipient of the remainder. - function initialize( - address payable _shareRecipient, - address payable _remainderRecipient - ) - external - initializer - { + function initialize(address payable _shareRecipient, address payable _remainderRecipient) external initializer { shareRecipient = _shareRecipient; remainderRecipient = _remainderRecipient; } @@ -125,4 +119,4 @@ contract SuperchainRevSharesCalculator is ISemver, Initializable { remainderRecipient = _remainderRecipient; emit RemainderRecipientUpdated(_remainderRecipient, oldRemainderRecipient); } -} \ No newline at end of file +} diff --git a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol index 0fb660b79b2..0e4ab8be7c2 100644 --- a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol @@ -37,7 +37,7 @@ contract FeeSplitter_TestInit is CommonTest { // Etch the FeeSplitter contract vm.etch(address(feeSplitter), vm.getDeployedCode("FeeSplitter.sol:FeeSplitter")); - + // Get the owner from ProxyAdmin _owner = IProxyAdmin(Predeploys.PROXY_ADMIN).owner(); } @@ -63,7 +63,9 @@ contract FeeSplitter_TestInit is CommonTest { uint256 _baseBalance, uint256 _l1Balance, uint256 _operatorBalance - ) internal { + ) + internal + { _mockFeeVaultForSuccessfulWithdrawal(Predeploys.SEQUENCER_FEE_WALLET, _sequencerBalance); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.BASE_FEE_VAULT, _baseBalance); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.L1_FEE_VAULT, _l1Balance); @@ -95,8 +97,7 @@ contract FeeSplitter_Initialize_Test is FeeSplitter_TestInit { vm.prank(_owner); IFeeSplitter(payable(impl)).initialize( - ISharesCalculator(address(_defaultSharesCalculator)), - _defaultFeeDisbursementInterval + ISharesCalculator(address(_defaultSharesCalculator)), _defaultFeeDisbursementInterval ); assertEq(address(IFeeSplitter(payable(impl)).shareCalculator()), address(_defaultSharesCalculator)); @@ -110,10 +111,10 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { /// @notice Test that receive function reverts when not during disbursement function test_feeSplitterReceive_WhenReceiveWindowIsClosed_Reverts(address _caller, uint256 _amount) public { vm.deal(_caller, _amount); - + vm.prank(_caller); vm.expectRevert(IFeeSplitter.FeeSplitter_ReceiveWindowClosed.selector); - (bool success,) = payable(address(feeSplitter)).call{value: _amount}(""); + (bool success,) = payable(address(feeSplitter)).call{ value: _amount }(""); } /// @notice Test receive function from non-approved vault reverts even during disbursement @@ -127,18 +128,15 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Mock the _isTransientDisbursing() function to return true // This allows us to test the sender validation logic - vm.mockCall( - address(feeSplitter), - abi.encodeWithSignature("_isTransientDisbursing()"), - abi.encode(true) - ); + vm.mockCall(address(feeSplitter), abi.encodeWithSignature("_isTransientDisbursing()"), abi.encode(true)); // Setup disbursement conditions but expect revert from non-approved sender vm.deal(_caller, _amount); - + vm.prank(_caller); - vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotApprovedVault.selector); // Now we test the actual sender validation - (bool success,) = payable(address(feeSplitter)).call{value: _amount}(""); + vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotApprovedVault.selector); // Now we test the actual sender + // validation + (bool success,) = payable(address(feeSplitter)).call{ value: _amount }(""); } /// @notice Test receive function works during disbursement from SequencerFeeVault @@ -150,11 +148,11 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { _mockFeeVaultForSuccessfulWithdrawal(Predeploys.BASE_FEE_VAULT, 0); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.L1_FEE_VAULT, 0); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.OPERATOR_FEE_VAULT, 0); - + // Mock shares calculator to return valid shares ShareInfo[] memory shareInfo = new ShareInfo[](1); shareInfo[0] = ShareInfo(payable(_defaultRevenueShareRecipient), _amount); - + // Get the actual shares calculator from the FeeSplitter address actualSharesCalculator = address(feeSplitter.shareCalculator()); vm.mockCall( @@ -168,7 +166,7 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); - + // Verify the recipient got the funds (proves receive function worked) assertEq(address(_defaultRevenueShareRecipient).balance, _amount); assertEq(address(feeSplitter).balance, 0); @@ -184,11 +182,11 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { _mockFeeVaultForSuccessfulWithdrawal(Predeploys.BASE_FEE_VAULT, _amount); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.L1_FEE_VAULT, 0); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.OPERATOR_FEE_VAULT, 0); - + // Mock shares calculator to return valid shares ShareInfo[] memory shareInfo = new ShareInfo[](1); shareInfo[0] = ShareInfo(payable(_defaultRevenueShareRecipient), _amount); - + // Get the actual shares calculator from the FeeSplitter address actualSharesCalculator = address(feeSplitter.shareCalculator()); vm.mockCall( @@ -202,7 +200,7 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); - + // Verify the recipient got the funds (proves receive function worked) assertEq(address(_defaultRevenueShareRecipient).balance, _amount); assertEq(address(feeSplitter).balance, 0); @@ -218,11 +216,11 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { _mockFeeVaultForSuccessfulWithdrawal(Predeploys.BASE_FEE_VAULT, 0); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.L1_FEE_VAULT, _amount); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.OPERATOR_FEE_VAULT, 0); - + // Mock shares calculator to return valid shares ShareInfo[] memory shareInfo = new ShareInfo[](1); shareInfo[0] = ShareInfo(payable(_defaultRevenueShareRecipient), _amount); - + // Get the actual shares calculator from the FeeSplitter address actualSharesCalculator = address(feeSplitter.shareCalculator()); vm.mockCall( @@ -236,7 +234,7 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); - + // Verify the recipient got the funds (proves receive function worked) assertEq(address(_defaultRevenueShareRecipient).balance, _amount); assertEq(address(feeSplitter).balance, 0); @@ -252,11 +250,11 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { _mockFeeVaultForSuccessfulWithdrawal(Predeploys.BASE_FEE_VAULT, 0); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.L1_FEE_VAULT, 0); _mockFeeVaultForSuccessfulWithdrawal(Predeploys.OPERATOR_FEE_VAULT, _amount); - + // Mock shares calculator to return valid shares ShareInfo[] memory shareInfo = new ShareInfo[](1); shareInfo[0] = ShareInfo(payable(_defaultRevenueShareRecipient), _amount); - + // Get the actual shares calculator from the FeeSplitter address actualSharesCalculator = address(feeSplitter.shareCalculator()); vm.mockCall( @@ -270,15 +268,15 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); - + // Verify the recipient got the funds (proves receive function worked) assertEq(address(_defaultRevenueShareRecipient).balance, _amount); assertEq(address(feeSplitter).balance, 0); assertEq(feeSplitter.lastDisbursementTime(), block.timestamp); - } + } } -/// @title FeeSplitter_DisburseFees_Test +/// @title FeeSplitter_DisburseFees_Test /// @notice Tests the disburseFees function of the `FeeSplitter` contract. contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { /// @notice Test disburseFees reverts when interval not reached @@ -290,7 +288,7 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { /// @notice Test disburseFees reverts when no fees collected function test_feeSplitterDisburseFees_WhenNoFeesCollected_Reverts() public { _setupStandardFeeVaultMocks(0, 0, 0, 0); - + vm.warp(block.timestamp + 25 hours); vm.expectRevert(IFeeSplitter.FeeSplitter_NoFeesCollected.selector); feeSplitter.disburseFees(); @@ -299,8 +297,12 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { /// @notice Test disburseFees fails when fee vault has wrong withdrawal network function test_feeSplitterDisburseFees_WhenFeeVaultWrongNetwork_Reverts() public { // Mock fee vault with L1 withdrawal network (invalid) - vm.mockCall(Predeploys.SEQUENCER_FEE_WALLET, abi.encodeCall(IFeeVault.withdrawalNetwork, ()), abi.encode(Types.WithdrawalNetwork.L1)); - + vm.mockCall( + Predeploys.SEQUENCER_FEE_WALLET, + abi.encodeCall(IFeeVault.withdrawalNetwork, ()), + abi.encode(Types.WithdrawalNetwork.L1) + ); + vm.warp(block.timestamp + 25 hours); vm.expectRevert(IFeeSplitter.FeeSplitter_FeeVaultMustWithdrawToL2.selector); feeSplitter.disburseFees(); @@ -309,9 +311,15 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { /// @notice Test disburseFees fails when fee vault has wrong recipient function test_feeSplitterDisburseFees_WhenFeeVaultWrongRecipient_Reverts() public { // Mock fee vault with wrong recipient - vm.mockCall(Predeploys.SEQUENCER_FEE_WALLET, abi.encodeCall(IFeeVault.withdrawalNetwork, ()), abi.encode(Types.WithdrawalNetwork.L2)); - vm.mockCall(Predeploys.SEQUENCER_FEE_WALLET, abi.encodeCall(IFeeVault.recipient, ()), abi.encode(address(0x123))); - + vm.mockCall( + Predeploys.SEQUENCER_FEE_WALLET, + abi.encodeCall(IFeeVault.withdrawalNetwork, ()), + abi.encode(Types.WithdrawalNetwork.L2) + ); + vm.mockCall( + Predeploys.SEQUENCER_FEE_WALLET, abi.encodeCall(IFeeVault.recipient, ()), abi.encode(address(0x123)) + ); + vm.warp(block.timestamp + 25 hours); vm.expectRevert(IFeeSplitter.FeeSplitter_FeeVaultMustWithdrawToFeeSplitter.selector); feeSplitter.disburseFees(); @@ -328,18 +336,21 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { // Calculate expected gross revenue uint256 expectedGrossRevenue = _sequencerAmount + _baseAmount + _l1Amount + _operatorAmount; - + // Setup mock shares calculator to return 50/50 split uint256 halfGrossRevenue = expectedGrossRevenue / 2; ShareInfo[] memory expectedShareInfo = new ShareInfo[](2); expectedShareInfo[0] = ShareInfo(payable(_defaultRevenueShareRecipient), halfGrossRevenue); - expectedShareInfo[1] = ShareInfo(payable(_defaultRevenueRemainderRecipient), expectedGrossRevenue - halfGrossRevenue); - + expectedShareInfo[1] = + ShareInfo(payable(_defaultRevenueRemainderRecipient), expectedGrossRevenue - halfGrossRevenue); + // Get the actual shares calculator from the FeeSplitter address actualSharesCalculator = address(feeSplitter.shareCalculator()); vm.mockCall( actualSharesCalculator, - abi.encodeCall(ISharesCalculator.getRecipientsAndValues, (_sequencerAmount, _baseAmount, _operatorAmount, _l1Amount)), + abi.encodeCall( + ISharesCalculator.getRecipientsAndValues, (_sequencerAmount, _baseAmount, _operatorAmount, _l1Amount) + ), abi.encode(expectedShareInfo) ); @@ -358,7 +369,10 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { // Verify recipients received their shares assertEq(address(_defaultRevenueShareRecipient).balance, revenueShareRecipientBalanceBefore + halfGrossRevenue); - assertEq(address(_defaultRevenueRemainderRecipient).balance, revenueRemainderRecipientBalanceBefore + (expectedGrossRevenue - halfGrossRevenue)); + assertEq( + address(_defaultRevenueRemainderRecipient).balance, + revenueRemainderRecipientBalanceBefore + (expectedGrossRevenue - halfGrossRevenue) + ); // Verify the fee vaults have no balance assertEq(address(Predeploys.SEQUENCER_FEE_WALLET).balance, 0); @@ -471,7 +485,7 @@ contract MockFeeVault { emit Withdrawal(value, RECIPIENT, msg.sender, WITHDRAWAL_NETWORK); if (WITHDRAWAL_NETWORK == Types.WithdrawalNetwork.L2) { - (bool success,) = RECIPIENT.call{value: value}(""); + (bool success,) = RECIPIENT.call{ value: value }(""); require(success, "FeeVault: failed to send ETH to L2 fee recipient"); } } From ffacbc0bf7b8be640fe6171cf6c87564671e1e37 Mon Sep 17 00:00:00 2001 From: funkornaut001 <107587461+funkornaut001@users.noreply.github.com> Date: Thu, 28 Aug 2025 10:45:50 -0500 Subject: [PATCH 23/23] fix: __gap to 46 --- packages/contracts-bedrock/src/L2/FeeVault.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 6c36d045954..71c090271ae 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -62,7 +62,7 @@ abstract contract FeeVault { uint8 private _configFlags; /// @notice Reserve extra slots in the storage layout for future upgrades, 50 in total. - uint256[44] private __gap; + uint256[46] private __gap; /// @notice Emitted each time a withdrawal occurs. This event will be deprecated /// in favor of the Withdrawal event containing the WithdrawalNetwork parameter.