From 6113ab06fdc477eaadffc2d095ff344a68e35387 Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Wed, 22 Oct 2025 12:25:19 -0300 Subject: [PATCH 01/11] fix: event consistency in receive events (#642) --- .../interfaces/L2/IFeeSplitter.sol | 2 +- .../snapshots/abi/FeeSplitter.json | 6 ++++++ .../contracts-bedrock/snapshots/semver-lock.json | 4 ++-- packages/contracts-bedrock/src/L2/FeeSplitter.sol | 6 ++++-- .../contracts-bedrock/test/L2/FeeSplitter.t.sol | 14 +++++++++++++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol b/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol index 8c10a4536e4..4e2fc06a8db 100644 --- a/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol +++ b/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol @@ -19,7 +19,7 @@ interface IFeeSplitter is ISemver { error FeeSplitter_ReceiveWindowClosed(); error FeeSplitter_SenderNotApprovedVault(); - event FeesReceived(address indexed sender, uint256 amount); + event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance); event FeeDisbursementIntervalUpdated(uint128 oldFeeDisbursementInterval, uint128 newFeeDisbursementInterval); event FeesDisbursed(ISharesCalculator.ShareInfo[] shareInfo, uint256 grossRevenue); event SharesCalculatorUpdated(address oldSharesCalculator, address newSharesCalculator); diff --git a/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json b/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json index 8535a7d886e..bd3c25794a6 100644 --- a/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json +++ b/packages/contracts-bedrock/snapshots/abi/FeeSplitter.json @@ -183,6 +183,12 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBalance", + "type": "uint256" } ], "name": "FeesReceived", diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 9025505a750..de768338b5e 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -64,8 +64,8 @@ "sourceCodeHash": "0x6d137fef431d75a8bf818444915fc39c8b1d93434a9af9971d96fb3170bc72b7" }, "src/L2/FeeSplitter.sol:FeeSplitter": { - "initCodeHash": "0x6426953a0a4e92722d5dd264f6b23069353ed84ada2462a36104cd73392e6a8c", - "sourceCodeHash": "0x09d876fcd1f7ea31627dae9a78b3c446d745ef67f0fb2b1feea6559e65875a58" + "initCodeHash": "0x823d3a12d5910b3826ee2a01dbd207d4188a8534aea3a8c3f68e2d5f5e0208eb", + "sourceCodeHash": "0xe03281da2da8d1099c5ded62de843424f8436a0f854b193ce10a9eed172dc252" }, "src/L2/GasPriceOracle.sol:GasPriceOracle": { "initCodeHash": "0x38ef70b2783dd45ad807afcf57972c7df4abaaeb5d16d17cdb451b9e931a9cbb", diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index e08c3a53313..8c53117f975 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -80,7 +80,8 @@ contract FeeSplitter is ISemver, Initializable { /// @notice Emitted when fees are received from FeeVaults. /// @param sender The FeeVault that sent the fees. /// @param amount The amount of fees received. - event FeesReceived(address indexed sender, uint256 amount); + /// @param newBalance The new balance after receiving fees. + event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance); /// @notice Emitted when the fee disbursement interval is updated. /// @param oldFeeDisbursementInterval The previous fee disbursement interval. @@ -119,7 +120,8 @@ contract FeeSplitter is ISemver, Initializable { ) { revert FeeSplitter_SenderNotApprovedVault(); } - emit FeesReceived({ sender: msg.sender, amount: msg.value }); + uint256 newBalance = address(this).balance; + emit FeesReceived(msg.sender, msg.value, newBalance); } /// @notice Withdraws funds from FeeVaults and disburses them to the recipients. diff --git a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol index e2702dfde7d..5317751b54e 100644 --- a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol @@ -22,7 +22,7 @@ import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; /// @notice Reusable test initialization for `FeeSplitter` tests. contract FeeSplitter_TestInit is CommonTest { // Events - event FeesReceived(address indexed sender, uint256 amount); + event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance); event FeeDisbursementIntervalUpdated(uint128 oldFeeDisbursementInterval, uint128 newFeeDisbursementInterval); event FeesDisbursed(ISharesCalculator.ShareInfo[] shareInfo, uint256 grossRevenue); event SharesCalculatorUpdated(address oldSharesCalculator, address newSharesCalculator); @@ -189,6 +189,9 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Fast forward time to allow disbursement vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + vm.expectEmit(true, true, true, true); + emit FeesReceived(Predeploys.SEQUENCER_FEE_WALLET, _amount, _amount); + // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); @@ -223,6 +226,9 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Fast forward time to allow disbursement vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + vm.expectEmit(true, true, true, true); + emit FeesReceived(Predeploys.BASE_FEE_VAULT, _amount, _amount); + // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); @@ -257,6 +263,9 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Fast forward time to allow disbursement vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + vm.expectEmit(true, true, true, true); + emit FeesReceived(Predeploys.L1_FEE_VAULT, _amount, _amount); + // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); @@ -291,6 +300,9 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { // Fast forward time to allow disbursement vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + vm.expectEmit(true, true, true, true); + emit FeesReceived(Predeploys.OPERATOR_FEE_VAULT, _amount, _amount); + // Call disburseFees - this will trigger the receive function during withdrawal feeSplitter.disburseFees(); From ff54dd498aa312b928c0d05be99e793a07612bf8 Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Thu, 23 Oct 2025 20:35:12 -0300 Subject: [PATCH 02/11] fix: add disbursement interval check (#648) --- packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol | 1 + packages/contracts-bedrock/src/L2/FeeSplitter.sol | 6 ++++++ packages/contracts-bedrock/test/L2/FeeSplitter.t.sol | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol b/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol index 4e2fc06a8db..ea21661a000 100644 --- a/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol +++ b/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol @@ -7,6 +7,7 @@ import { ISharesCalculator } from "interfaces/L2/ISharesCalculator.sol"; interface IFeeSplitter is ISemver { event Initialized(uint8 version); error FeeSplitter_ExceedsMaxFeeDisbursementTime(); + error FeeSplitter_FeeDisbursementIntervalCannotBeZero(); error FeeSplitter_SharesCalculatorCannotBeZero(); error FeeSplitter_DisbursementIntervalNotReached(); error FeeSplitter_FeeShareInfoEmpty(); diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index 8c53117f975..11e5442423a 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -24,6 +24,9 @@ contract FeeSplitter is ISemver, Initializable { /// @notice Thrown when the fee disbursement interval exceeds the maximum allowed. error FeeSplitter_ExceedsMaxFeeDisbursementTime(); + /// @notice Thrown when the fee disbursement interval is set to zero. + error FeeSplitter_FeeDisbursementIntervalCannotBeZero(); + /// @notice Thrown when the share calculator address is zero. error FeeSplitter_SharesCalculatorCannotBeZero(); @@ -185,6 +188,9 @@ contract FeeSplitter is ISemver, Initializable { if (msg.sender != IProxyAdmin(Predeploys.PROXY_ADMIN).owner()) { revert FeeSplitter_OnlyProxyAdminOwner(); } + if (_newFeeDisbursementInterval == 0) { + revert FeeSplitter_FeeDisbursementIntervalCannotBeZero(); + } if (_newFeeDisbursementInterval > MAX_DISBURSEMENT_INTERVAL) { revert FeeSplitter_ExceedsMaxFeeDisbursementTime(); } diff --git a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol index 5317751b54e..54f2a6330ae 100644 --- a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol @@ -579,6 +579,13 @@ contract FeeSplitter_SetFeeDisbursementInterval_Test is FeeSplitter_TestInit { feeSplitter.setFeeDisbursementInterval(48 hours); } + /// @notice Test setFeeDisbursementInterval reverts when interval is zero + function test_feeSplitterSetFeeDisbursementInterval_whenIntervalZero_reverts() public { + vm.prank(_owner); + vm.expectRevert(IFeeSplitter.FeeSplitter_FeeDisbursementIntervalCannotBeZero.selector); + feeSplitter.setFeeDisbursementInterval(0); + } + /// @notice Test setFeeDisbursementInterval reverts when interval is too long function testFuzz_feeSplitterSetFeeDisbursementInterval_whenIntervalTooLong_reverts(uint256 _disbursementInterval) public From 89da7d2a58a72e40a3cda2b4616e9c496b703046 Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Thu, 23 Oct 2025 20:56:12 -0300 Subject: [PATCH 03/11] fix: function visibility (#641) --- .../interfaces/L2/ISharesCalculator.sol | 16 ++++++++-------- .../contracts-bedrock/src/L2/FeeSplitter.sol | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/contracts-bedrock/interfaces/L2/ISharesCalculator.sol b/packages/contracts-bedrock/interfaces/L2/ISharesCalculator.sol index b47ce282d4a..f7935f1bb11 100644 --- a/packages/contracts-bedrock/interfaces/L2/ISharesCalculator.sol +++ b/packages/contracts-bedrock/interfaces/L2/ISharesCalculator.sol @@ -16,16 +16,16 @@ interface ISharesCalculator { /// @notice Returns the recipients and amounts for fee distribution. /// @dev Any implementation MUST return ShareInfo where the sum of all amounts equals /// the total revenue (sum of all vault balances) as it will revert otherwise - /// @param _sequencerFeeVaultBalance Balance of the sequencer fee vault. - /// @param _baseFeeVaultBalance Balance of the base fee vault. - /// @param _operatorFeeVaultBalance Balance of the operator fee vault. - /// @param _l1FeeVaultBalance Balance of the L1 fee vault. + /// @param _sequencerFeeRevenue Balance of the sequencer fee vault. + /// @param _baseFeeRevenue Balance of the base fee vault. + /// @param _operatorFeeRevenue Balance of the operator fee vault. + /// @param _l1FeeRevenue Balance of the L1 fee vault. /// @return shareInfo Array of ShareInfo structs containing recipients and amounts. function getRecipientsAndAmounts( - uint256 _sequencerFeeVaultBalance, - uint256 _baseFeeVaultBalance, - uint256 _operatorFeeVaultBalance, - uint256 _l1FeeVaultBalance + uint256 _sequencerFeeRevenue, + uint256 _baseFeeRevenue, + uint256 _operatorFeeRevenue, + uint256 _l1FeeRevenue ) external view diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index 11e5442423a..fdffea79b03 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -115,7 +115,7 @@ contract FeeSplitter is ISemver, Initializable { } /// @dev Receives ETH fees withdrawn from L2 FeeVaults. - receive() external payable virtual { + receive() external payable { if (!_isTransientDisbursing()) revert FeeSplitter_ReceiveWindowClosed(); if ( msg.sender != Predeploys.SEQUENCER_FEE_WALLET && msg.sender != Predeploys.BASE_FEE_VAULT From e099ef56b10f0fcc411203c4d970bb6ac4ebf44d Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Thu, 23 Oct 2025 20:56:52 -0300 Subject: [PATCH 04/11] chore: improve test naming (#651) --- packages/contracts-bedrock/test/L2/FeeVault.t.sol | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/contracts-bedrock/test/L2/FeeVault.t.sol b/packages/contracts-bedrock/test/L2/FeeVault.t.sol index 03ae05ec6b5..1cfee1b57ea 100644 --- a/packages/contracts-bedrock/test/L2/FeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeVault.t.sol @@ -33,13 +33,6 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { feeVault.setWithdrawalNetwork(Types.WithdrawalNetwork.L2); } - /// @notice Tests that the l1 fee wallet is correct. - function test_constructor_succeeds() external view { - assertEq(feeVault.RECIPIENT(), recipient); - assertEq(feeVault.MIN_WITHDRAWAL_AMOUNT(), minWithdrawalAmount); - assertEq(uint8(feeVault.WITHDRAWAL_NETWORK()), uint8(withdrawalNetwork)); - } - /// @notice Tests that the initialize function succeeds. function test_initialize_succeeds() external view { assertEq(feeVault.recipient(), recipient); @@ -55,6 +48,13 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { feeVault.initialize(recipient, minWithdrawalAmount, Types.WithdrawalNetwork.L1); } + /// @notice Tests that the immutable values match the storage getters. + function test_immutableMatchesStorageVariables_succeeds() external view { + assertEq(feeVault.RECIPIENT(), feeVault.recipient()); + assertEq(feeVault.MIN_WITHDRAWAL_AMOUNT(), feeVault.minWithdrawalAmount()); + assertEq(uint8(feeVault.WITHDRAWAL_NETWORK()), uint8(feeVault.withdrawalNetwork())); + } + /// @notice Tests that the fee feeVault is able to receive ETH. function test_receive_succeeds() external { uint256 balance = address(feeVault).balance; From 78745eace1edfae59219eac04cb89931adf92f00 Mon Sep 17 00:00:00 2001 From: Disco <131301107+0xDiscotech@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:32:41 -0300 Subject: [PATCH 05/11] fix: add missing fee splitter and op fee vault on go files (#639) --- op-chain-ops/devkeys/devkeys.go | 4 + .../genesis/withdrawal_network_test.go | 9 +- op-deployer/pkg/deployer/inspect/semvers.go | 4 + .../deployer/integration_test/apply_test.go | 6 + .../pkg/deployer/pipeline/l2genesis.go | 2 - .../pkg/deployer/pipeline/l2genesis_test.go | 5 - op-e2e/bindings/feesplitter.go | 1154 ++++++++++++++ op-e2e/bindings/operatorfeevault.go | 1389 +++++++++++++++++ op-service/predeploys/addresses.go | 3 + 9 files changed, 2567 insertions(+), 9 deletions(-) create mode 100644 op-e2e/bindings/feesplitter.go create mode 100644 op-e2e/bindings/operatorfeevault.go diff --git a/op-chain-ops/devkeys/devkeys.go b/op-chain-ops/devkeys/devkeys.go index 0e2e8ad33ef..9c754112621 100644 --- a/op-chain-ops/devkeys/devkeys.go +++ b/op-chain-ops/devkeys/devkeys.go @@ -160,6 +160,8 @@ const ( SystemConfigOwner ChainOperatorRole = 10 // OperatorFeeVaultRecipientRole is the key that receives from the OperatorFeeVault predeploy OperatorFeeVaultRecipientRole ChainOperatorRole = 11 + // ChainFeesRecipientRole is the key that receives the chain's share from the FeeSplitter + ChainFeesRecipientRole ChainOperatorRole = 12 ) func (role ChainOperatorRole) String() string { @@ -188,6 +190,8 @@ func (role ChainOperatorRole) String() string { return "operator-fee-vault-recipient" case SystemConfigOwner: return "system-config-owner" + case ChainFeesRecipientRole: + return "chain-fees-recipient" default: return fmt.Sprintf("unknown-operator-%d", uint64(role)) } diff --git a/op-chain-ops/genesis/withdrawal_network_test.go b/op-chain-ops/genesis/withdrawal_network_test.go index 624cbc0efe7..018b20117e0 100644 --- a/op-chain-ops/genesis/withdrawal_network_test.go +++ b/op-chain-ops/genesis/withdrawal_network_test.go @@ -83,18 +83,21 @@ func TestWithdrawalNetworkInlineJSON(t *testing.T) { BaseFeeVaultWithdrawalNetwork WithdrawalNetwork `json:"baseFeeVaultWithdrawalNetwork"` L1FeeVaultWithdrawalNetwork WithdrawalNetwork `json:"l1FeeVaultWithdrawalNetwork"` SequencerFeeVaultWithdrawalNetwork WithdrawalNetwork `json:"sequencerFeeVaultWithdrawalNetwork"` + OperatorFeeVaultWithdrawalNetwork WithdrawalNetwork `json:"operatorFeeVaultWithdrawalNetwork"` } jsonString := `{ "baseFeeVaultWithdrawalNetwork": "remote", "l1FeeVaultWithdrawalNetwork": "local", - "sequencerFeeVaultWithdrawalNetwork": "local" + "sequencerFeeVaultWithdrawalNetwork": "local", + "operatorFeeVaultWithdrawalNetwork": "local" }` intJsonString := `{ "baseFeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 1, - "sequencerFeeVaultWithdrawalNetwork": 1 + "sequencerFeeVaultWithdrawalNetwork": 1, + "operatorFeeVaultWithdrawalNetwork": 1 }` t.Run("StringMarshaling", func(t *testing.T) { @@ -104,6 +107,7 @@ func TestWithdrawalNetworkInlineJSON(t *testing.T) { require.Equal(t, WithdrawalNetwork("remote"), decoded.BaseFeeVaultWithdrawalNetwork) require.Equal(t, WithdrawalNetwork("local"), decoded.L1FeeVaultWithdrawalNetwork) require.Equal(t, WithdrawalNetwork("local"), decoded.SequencerFeeVaultWithdrawalNetwork) + require.Equal(t, WithdrawalNetwork("local"), decoded.OperatorFeeVaultWithdrawalNetwork) encoded, err := json.Marshal(decoded) require.NoError(t, err) @@ -118,6 +122,7 @@ func TestWithdrawalNetworkInlineJSON(t *testing.T) { require.Equal(t, WithdrawalNetwork("remote"), decoded.BaseFeeVaultWithdrawalNetwork) require.Equal(t, WithdrawalNetwork("local"), decoded.L1FeeVaultWithdrawalNetwork) require.Equal(t, WithdrawalNetwork("local"), decoded.SequencerFeeVaultWithdrawalNetwork) + require.Equal(t, WithdrawalNetwork("local"), decoded.OperatorFeeVaultWithdrawalNetwork) encoded, err := json.Marshal(decoded) require.NoError(t, err) diff --git a/op-deployer/pkg/deployer/inspect/semvers.go b/op-deployer/pkg/deployer/inspect/semvers.go index 232f1d4bd85..e373adf09fd 100644 --- a/op-deployer/pkg/deployer/inspect/semvers.go +++ b/op-deployer/pkg/deployer/inspect/semvers.go @@ -102,8 +102,10 @@ type L2PredeploySemvers struct { OptimismMintableERC721Factory string BaseFeeVault string L1FeeVault string + OperatorFeeVault string SchemaRegistry string EAS string + FeeSplitter string CrossL2Inbox string L2toL2CrossDomainMessenger string SuperchainETHBridge string @@ -153,8 +155,10 @@ func L2Semvers(cfg L2SemversConfig) (*L2PredeploySemvers, error) { {predeploys.OptimismMintableERC721FactoryAddr, &ps.OptimismMintableERC721Factory, "OptimismMintableERC721Factory"}, {predeploys.BaseFeeVaultAddr, &ps.BaseFeeVault, "BaseFeeVault"}, {predeploys.L1FeeVaultAddr, &ps.L1FeeVault, "L1FeeVault"}, + {predeploys.OperatorFeeVaultAddr, &ps.OperatorFeeVault, "OperatorFeeVault"}, {predeploys.SchemaRegistryAddr, &ps.SchemaRegistry, "SchemaRegistry"}, {predeploys.EASAddr, &ps.EAS, "EAS"}, + {predeploys.FeeSplitterAddr, &ps.FeeSplitter, "FeeSplitter"}, } for _, contract := range contracts { semver, err := ReadSemver(host, contract.Address) diff --git a/op-deployer/pkg/deployer/integration_test/apply_test.go b/op-deployer/pkg/deployer/integration_test/apply_test.go index 81597b56d5d..ab40a3f3067 100644 --- a/op-deployer/pkg/deployer/integration_test/apply_test.go +++ b/op-deployer/pkg/deployer/integration_test/apply_test.go @@ -596,6 +596,12 @@ func TestInvalidL2Genesis(t *testing.T) { "sequencerFeeVaultRecipient": nil, }, }, + { + name: "operator fee vault recipient not set", + overrides: map[string]any{ + "operatorFeeVaultRecipient": nil, + }, + }, { name: "l1 chain ID not set", overrides: map[string]any{ diff --git a/op-deployer/pkg/deployer/pipeline/l2genesis.go b/op-deployer/pkg/deployer/pipeline/l2genesis.go index 3feabb19be1..19dec48dc3c 100644 --- a/op-deployer/pkg/deployer/pipeline/l2genesis.go +++ b/op-deployer/pkg/deployer/pipeline/l2genesis.go @@ -33,7 +33,6 @@ type l2GenesisOverrides struct { OperatorFeeVaultWithdrawalNetwork genesis.WithdrawalNetwork `json:"operatorFeeVaultWithdrawalNetwork"` EnableGovernance bool `json:"enableGovernance"` GovernanceTokenOwner common.Address `json:"governanceTokenOwner"` - UseRevenueShare bool `json:"useRevenueShare"` } func GenerateL2Genesis(pEnv *Env, intent *state.Intent, bundle ArtifactsBundle, st *state.State, chainID common.Hash) error { @@ -176,6 +175,5 @@ func defaultOverrides() l2GenesisOverrides { OperatorFeeVaultWithdrawalNetwork: "local", EnableGovernance: false, GovernanceTokenOwner: standard.GovernanceTokenOwner, - UseRevenueShare: true, } } diff --git a/op-deployer/pkg/deployer/pipeline/l2genesis_test.go b/op-deployer/pkg/deployer/pipeline/l2genesis_test.go index 003e39ddf0a..0b7e6839151 100644 --- a/op-deployer/pkg/deployer/pipeline/l2genesis_test.go +++ b/op-deployer/pkg/deployer/pipeline/l2genesis_test.go @@ -55,7 +55,6 @@ func TestCalculateL2GenesisOverrides(t *testing.T) { OperatorFeeVaultWithdrawalNetwork: "local", EnableGovernance: false, GovernanceTokenOwner: standard.GovernanceTokenOwner, - UseRevenueShare: true, }, expectedSchedule: func() *genesis.UpgradeScheduleDeployConfig { return standard.DefaultHardforkScheduleForTag("") @@ -78,7 +77,6 @@ func TestCalculateL2GenesisOverrides(t *testing.T) { "enableGovernance": true, "governanceTokenOwner": "0x1111111111111111111111111111111111111111", "l2GenesisInteropTimeOffset": "0x1234", - "useRevenueShare": false, "chainFeesRecipient": "0x0000000000000000000000000000000000005678", }, }, @@ -96,7 +94,6 @@ func TestCalculateL2GenesisOverrides(t *testing.T) { OperatorFeeVaultWithdrawalNetwork: "remote", EnableGovernance: true, GovernanceTokenOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"), - UseRevenueShare: false, }, expectedSchedule: func() *genesis.UpgradeScheduleDeployConfig { sched := standard.DefaultHardforkScheduleForTag("") @@ -125,7 +122,6 @@ func TestCalculateL2GenesisOverrides(t *testing.T) { "enableGovernance": true, "governanceTokenOwner": "0x1111111111111111111111111111111111111111", "l2GenesisInteropTimeOffset": "0x1234", - "useRevenueShare": true, }, }, expectError: false, @@ -141,7 +137,6 @@ func TestCalculateL2GenesisOverrides(t *testing.T) { OperatorFeeVaultWithdrawalNetwork: "remote", EnableGovernance: true, GovernanceTokenOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"), - UseRevenueShare: true, }, expectedSchedule: func() *genesis.UpgradeScheduleDeployConfig { sched := standard.DefaultHardforkScheduleForTag("") diff --git a/op-e2e/bindings/feesplitter.go b/op-e2e/bindings/feesplitter.go new file mode 100644 index 00000000000..f1f9d973410 --- /dev/null +++ b/op-e2e/bindings/feesplitter.go @@ -0,0 +1,1154 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ISharesCalculatorShareInfo is an auto generated low-level Go binding around an user-defined struct. +type ISharesCalculatorShareInfo struct { + Recipient common.Address + Amount *big.Int +} + +// FeeSplitterMetaData contains all meta data concerning the FeeSplitter contract. +var FeeSplitterMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"MAX_DISBURSEMENT_INTERVAL\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disburseFees\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"feeDisbursementInterval\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_sharesCalculator\",\"type\":\"address\",\"internalType\":\"contractISharesCalculator\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastDisbursementTime\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setFeeDisbursementInterval\",\"inputs\":[{\"name\":\"_newFeeDisbursementInterval\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setSharesCalculator\",\"inputs\":[{\"name\":\"_newSharesCalculator\",\"type\":\"address\",\"internalType\":\"contractISharesCalculator\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"sharesCalculator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISharesCalculator\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"FeeDisbursementIntervalUpdated\",\"inputs\":[{\"name\":\"oldFeeDisbursementInterval\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"},{\"name\":\"newFeeDisbursementInterval\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeesDisbursed\",\"inputs\":[{\"name\":\"shareInfo\",\"type\":\"tuple[]\",\"indexed\":false,\"internalType\":\"structISharesCalculator.ShareInfo[]\",\"components\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"addresspayable\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"grossRevenue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeesReceived\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newBalance\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SharesCalculatorUpdated\",\"inputs\":[{\"name\":\"oldSharesCalculator\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newSharesCalculator\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"FeeSplitter_DisbursementIntervalNotReached\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_ExceedsMaxFeeDisbursementTime\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_FailedToSendToRevenueShareRecipient\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_FeeDisbursementIntervalCannotBeZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_FeeShareInfoEmpty\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_FeeVaultMustWithdrawToFeeSplitter\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_FeeVaultMustWithdrawToL2\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_NoFeesCollected\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_OnlyProxyAdminOwner\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_ReceiveWindowClosed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_SenderNotApprovedVault\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_SharesCalculatorCannotBeZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeSplitter_SharesCalculatorMalformedOutput\",\"inputs\":[]}]", + Bin: "0x6080604052348015600e575f80fd5b5060156019565b60d4565b5f54610100900460ff161560835760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116101560d2575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611344806100e15f395ff3fe608060405260043610610096575f3560e01c80637dfbd04911610066578063b87ea8d41161004c578063b87ea8d41461031b578063c4d66de81461032f578063d61a398b1461034e575f80fd5b80637dfbd049146102e55780637fc81bb7146102fc575f80fd5b80630a7617b3146101e55780630c0544a314610206578063394d27311461026857806354fd4d5014610290575f80fd5b366101e1577fe3007e9730850b5618eacb0537bef0cf0f1600267ae8549e472449d77b731e455c6100f3576040517f17617f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b337342000000000000000000000000000000000000111480159061012b57503373420000000000000000000000000000000000001914155b801561014b57503373420000000000000000000000000000000000001a14155b801561016b57503373420000000000000000000000000000000000001b14155b156101a2576040517f9dcde10900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805134815247602082018190529133917f213e72af0d3613bd643cff3059f872c1015e6541624e37872bf95eefbaf220a8910160405180910390a2005b5f80fd5b3480156101f0575f80fd5b506102046101ff366004610f9e565b6103a4565b005b348015610211575f80fd5b506001546102429070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610273575f80fd5b50600154610242906fffffffffffffffffffffffffffffffff1681565b34801561029b575f80fd5b506102d86040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161025f9190610fb9565b3480156102f0575f80fd5b506102426301e1338081565b348015610307575f80fd5b5061020461031636600461100c565b610566565b348015610326575f80fd5b50610204610759565b34801561033a575f80fd5b50610204610349366004610f9e565b610b3d565b348015610359575f80fd5b505f5461037f9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161025f565b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610401573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610425919061103b565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610489576040517f38bac74200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166104d6576040517f99c6ec0800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff85161790945560408051949093049091168084526020840191909152917f16417cc372deec0caee5f52e2ad77a5f07b4591fd56b4ff31b6e20f817d4daeb91015b60405180910390a15050565b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e7919061103b565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461064b576040517f38bac74200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806fffffffffffffffffffffffffffffffff165f03610696576040517fcf85916100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6301e133806fffffffffffffffffffffffffffffffff821611156106e6576040517f30b9f35e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546fffffffffffffffffffffffffffffffff8381167001000000000000000000000000000000008181028385161790945560408051949093049091168084526020840191909152917f4492086b630ed3846eec0979dd87a71c814ceb1c6dab80ab81e3450b21e4de28910161055a565b60015461078e906fffffffffffffffffffffffffffffffff700100000000000000000000000000000000820481169116611083565b6fffffffffffffffffffffffffffffffff164210156107d9576040517f1e4a9f3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016426fffffffffffffffffffffffffffffffff1617815561081e90610d33565b5f61083c734200000000000000000000000000000000000011610d59565b90505f61085c734200000000000000000000000000000000000019610d59565b90505f61087c73420000000000000000000000000000000000001a610d59565b90505f61089c73420000000000000000000000000000000000001b610d59565b90506108a75f610d33565b5f82826108b486886110b3565b6108be91906110b3565b6108c891906110b3565b9050805f03610903576040517fc8972e5200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517f54e7f42d000000000000000000000000000000000000000000000000000000008152600481018890526024810187905260448101859052606481018690526201000090910473ffffffffffffffffffffffffffffffffffffffff16906354e7f42d906084015f60405180830381865afa158015610989573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526109ce919081019061116b565b905080515f03610a0a576040517f763970d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805b8251811015610ac1575f838281518110610a2957610a2961123a565b60200260200101515f015190505f848381518110610a4957610a4961123a565b6020026020010151602001519050805f03610a65575050610ab9565b5f610a708383610f56565b905080610aa9576040517fd68d1b1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ab382866110b3565b94505050505b600101610a0d565b50828114610afb576040517f9c01eac000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f73f9a13241a1848ec157967f3a85601709353e616f1f2605d818c0f2d21774df8284604051610b2c929190611267565b60405180910390a150505050505050565b5f54610100900460ff1615808015610b5b57505f54600160ff909116105b80610b745750303b158015610b7457505f5460ff166001145b610c04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610c60575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851602179055600180546fffffffffffffffffffffffffffffffff1672015180000000000000000000000000000000001790558015610d2f575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161055a565b5050565b807fe3007e9730850b5618eacb0537bef0cf0f1600267ae8549e472449d77b731e455d50565b5f60018273ffffffffffffffffffffffffffffffffffffffff166382356d8a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dc99190611302565b6001811115610dda57610dda6112d5565b14610e11576040517fb4726cbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff166366d003ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e95919061103b565b73ffffffffffffffffffffffffffffffffffffffff1614610ee2576040517fc3380cef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16633ccfd60b6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015610f2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f509190611320565b92915050565b5f610f62835a84610f69565b9392505050565b5f805f805f858888f1949350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f9b575f80fd5b50565b5f60208284031215610fae575f80fd5b8135610f6281610f7a565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f6020828403121561101c575f80fd5b81356fffffffffffffffffffffffffffffffff81168114610f62575f80fd5b5f6020828403121561104b575f80fd5b8151610f6281610f7a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6fffffffffffffffffffffffffffffffff8181168382160190808211156110ac576110ac611056565b5092915050565b80820180821115610f5057610f50611056565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715611116576111166110c6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611163576111636110c6565b604052919050565b5f602080838503121561117c575f80fd5b825167ffffffffffffffff80821115611193575f80fd5b818501915085601f8301126111a6575f80fd5b8151818111156111b8576111b86110c6565b6111c6848260051b0161111c565b818152848101925060069190911b8301840190878211156111e5575f80fd5b928401925b8184101561122f5760408489031215611201575f80fd5b6112096110f3565b845161121481610f7a565b815284860151868201528352604090930192918401916111ea565b979650505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b604080825283518282018190525f91906020906060850190828801855b828110156112bf578151805173ffffffffffffffffffffffffffffffffffffffff168552850151858501529285019290840190600101611284565b5050508093505050508260208301529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215611312575f80fd5b815160028110610f62575f80fd5b5f60208284031215611330575f80fd5b505191905056fea164736f6c6343000819000a", +} + +// FeeSplitterABI is the input ABI used to generate the binding from. +// Deprecated: Use FeeSplitterMetaData.ABI instead. +var FeeSplitterABI = FeeSplitterMetaData.ABI + +// FeeSplitterBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use FeeSplitterMetaData.Bin instead. +var FeeSplitterBin = FeeSplitterMetaData.Bin + +// DeployFeeSplitter deploys a new Ethereum contract, binding an instance of FeeSplitter to it. +func DeployFeeSplitter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *FeeSplitter, error) { + parsed, err := FeeSplitterMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(FeeSplitterBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &FeeSplitter{FeeSplitterCaller: FeeSplitterCaller{contract: contract}, FeeSplitterTransactor: FeeSplitterTransactor{contract: contract}, FeeSplitterFilterer: FeeSplitterFilterer{contract: contract}}, nil +} + +// FeeSplitter is an auto generated Go binding around an Ethereum contract. +type FeeSplitter struct { + FeeSplitterCaller // Read-only binding to the contract + FeeSplitterTransactor // Write-only binding to the contract + FeeSplitterFilterer // Log filterer for contract events +} + +// FeeSplitterCaller is an auto generated read-only Go binding around an Ethereum contract. +type FeeSplitterCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FeeSplitterTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FeeSplitterTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FeeSplitterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FeeSplitterFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FeeSplitterSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FeeSplitterSession struct { + Contract *FeeSplitter // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FeeSplitterCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FeeSplitterCallerSession struct { + Contract *FeeSplitterCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FeeSplitterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FeeSplitterTransactorSession struct { + Contract *FeeSplitterTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FeeSplitterRaw is an auto generated low-level Go binding around an Ethereum contract. +type FeeSplitterRaw struct { + Contract *FeeSplitter // Generic contract binding to access the raw methods on +} + +// FeeSplitterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FeeSplitterCallerRaw struct { + Contract *FeeSplitterCaller // Generic read-only contract binding to access the raw methods on +} + +// FeeSplitterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FeeSplitterTransactorRaw struct { + Contract *FeeSplitterTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFeeSplitter creates a new instance of FeeSplitter, bound to a specific deployed contract. +func NewFeeSplitter(address common.Address, backend bind.ContractBackend) (*FeeSplitter, error) { + contract, err := bindFeeSplitter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FeeSplitter{FeeSplitterCaller: FeeSplitterCaller{contract: contract}, FeeSplitterTransactor: FeeSplitterTransactor{contract: contract}, FeeSplitterFilterer: FeeSplitterFilterer{contract: contract}}, nil +} + +// NewFeeSplitterCaller creates a new read-only instance of FeeSplitter, bound to a specific deployed contract. +func NewFeeSplitterCaller(address common.Address, caller bind.ContractCaller) (*FeeSplitterCaller, error) { + contract, err := bindFeeSplitter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FeeSplitterCaller{contract: contract}, nil +} + +// NewFeeSplitterTransactor creates a new write-only instance of FeeSplitter, bound to a specific deployed contract. +func NewFeeSplitterTransactor(address common.Address, transactor bind.ContractTransactor) (*FeeSplitterTransactor, error) { + contract, err := bindFeeSplitter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FeeSplitterTransactor{contract: contract}, nil +} + +// NewFeeSplitterFilterer creates a new log filterer instance of FeeSplitter, bound to a specific deployed contract. +func NewFeeSplitterFilterer(address common.Address, filterer bind.ContractFilterer) (*FeeSplitterFilterer, error) { + contract, err := bindFeeSplitter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FeeSplitterFilterer{contract: contract}, nil +} + +// bindFeeSplitter binds a generic wrapper to an already deployed contract. +func bindFeeSplitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FeeSplitterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FeeSplitter *FeeSplitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FeeSplitter.Contract.FeeSplitterCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FeeSplitter *FeeSplitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FeeSplitter.Contract.FeeSplitterTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FeeSplitter *FeeSplitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FeeSplitter.Contract.FeeSplitterTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FeeSplitter *FeeSplitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FeeSplitter.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FeeSplitter *FeeSplitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FeeSplitter.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FeeSplitter *FeeSplitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FeeSplitter.Contract.contract.Transact(opts, method, params...) +} + +// MAXDISBURSEMENTINTERVAL is a free data retrieval call binding the contract method 0x7dfbd049. +// +// Solidity: function MAX_DISBURSEMENT_INTERVAL() view returns(uint128) +func (_FeeSplitter *FeeSplitterCaller) MAXDISBURSEMENTINTERVAL(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FeeSplitter.contract.Call(opts, &out, "MAX_DISBURSEMENT_INTERVAL") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MAXDISBURSEMENTINTERVAL is a free data retrieval call binding the contract method 0x7dfbd049. +// +// Solidity: function MAX_DISBURSEMENT_INTERVAL() view returns(uint128) +func (_FeeSplitter *FeeSplitterSession) MAXDISBURSEMENTINTERVAL() (*big.Int, error) { + return _FeeSplitter.Contract.MAXDISBURSEMENTINTERVAL(&_FeeSplitter.CallOpts) +} + +// MAXDISBURSEMENTINTERVAL is a free data retrieval call binding the contract method 0x7dfbd049. +// +// Solidity: function MAX_DISBURSEMENT_INTERVAL() view returns(uint128) +func (_FeeSplitter *FeeSplitterCallerSession) MAXDISBURSEMENTINTERVAL() (*big.Int, error) { + return _FeeSplitter.Contract.MAXDISBURSEMENTINTERVAL(&_FeeSplitter.CallOpts) +} + +// FeeDisbursementInterval is a free data retrieval call binding the contract method 0x0c0544a3. +// +// Solidity: function feeDisbursementInterval() view returns(uint128) +func (_FeeSplitter *FeeSplitterCaller) FeeDisbursementInterval(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FeeSplitter.contract.Call(opts, &out, "feeDisbursementInterval") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FeeDisbursementInterval is a free data retrieval call binding the contract method 0x0c0544a3. +// +// Solidity: function feeDisbursementInterval() view returns(uint128) +func (_FeeSplitter *FeeSplitterSession) FeeDisbursementInterval() (*big.Int, error) { + return _FeeSplitter.Contract.FeeDisbursementInterval(&_FeeSplitter.CallOpts) +} + +// FeeDisbursementInterval is a free data retrieval call binding the contract method 0x0c0544a3. +// +// Solidity: function feeDisbursementInterval() view returns(uint128) +func (_FeeSplitter *FeeSplitterCallerSession) FeeDisbursementInterval() (*big.Int, error) { + return _FeeSplitter.Contract.FeeDisbursementInterval(&_FeeSplitter.CallOpts) +} + +// LastDisbursementTime is a free data retrieval call binding the contract method 0x394d2731. +// +// Solidity: function lastDisbursementTime() view returns(uint128) +func (_FeeSplitter *FeeSplitterCaller) LastDisbursementTime(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FeeSplitter.contract.Call(opts, &out, "lastDisbursementTime") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// LastDisbursementTime is a free data retrieval call binding the contract method 0x394d2731. +// +// Solidity: function lastDisbursementTime() view returns(uint128) +func (_FeeSplitter *FeeSplitterSession) LastDisbursementTime() (*big.Int, error) { + return _FeeSplitter.Contract.LastDisbursementTime(&_FeeSplitter.CallOpts) +} + +// LastDisbursementTime is a free data retrieval call binding the contract method 0x394d2731. +// +// Solidity: function lastDisbursementTime() view returns(uint128) +func (_FeeSplitter *FeeSplitterCallerSession) LastDisbursementTime() (*big.Int, error) { + return _FeeSplitter.Contract.LastDisbursementTime(&_FeeSplitter.CallOpts) +} + +// SharesCalculator is a free data retrieval call binding the contract method 0xd61a398b. +// +// Solidity: function sharesCalculator() view returns(address) +func (_FeeSplitter *FeeSplitterCaller) SharesCalculator(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FeeSplitter.contract.Call(opts, &out, "sharesCalculator") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// SharesCalculator is a free data retrieval call binding the contract method 0xd61a398b. +// +// Solidity: function sharesCalculator() view returns(address) +func (_FeeSplitter *FeeSplitterSession) SharesCalculator() (common.Address, error) { + return _FeeSplitter.Contract.SharesCalculator(&_FeeSplitter.CallOpts) +} + +// SharesCalculator is a free data retrieval call binding the contract method 0xd61a398b. +// +// Solidity: function sharesCalculator() view returns(address) +func (_FeeSplitter *FeeSplitterCallerSession) SharesCalculator() (common.Address, error) { + return _FeeSplitter.Contract.SharesCalculator(&_FeeSplitter.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_FeeSplitter *FeeSplitterCaller) Version(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _FeeSplitter.contract.Call(opts, &out, "version") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_FeeSplitter *FeeSplitterSession) Version() (string, error) { + return _FeeSplitter.Contract.Version(&_FeeSplitter.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_FeeSplitter *FeeSplitterCallerSession) Version() (string, error) { + return _FeeSplitter.Contract.Version(&_FeeSplitter.CallOpts) +} + +// DisburseFees is a paid mutator transaction binding the contract method 0xb87ea8d4. +// +// Solidity: function disburseFees() returns() +func (_FeeSplitter *FeeSplitterTransactor) DisburseFees(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FeeSplitter.contract.Transact(opts, "disburseFees") +} + +// DisburseFees is a paid mutator transaction binding the contract method 0xb87ea8d4. +// +// Solidity: function disburseFees() returns() +func (_FeeSplitter *FeeSplitterSession) DisburseFees() (*types.Transaction, error) { + return _FeeSplitter.Contract.DisburseFees(&_FeeSplitter.TransactOpts) +} + +// DisburseFees is a paid mutator transaction binding the contract method 0xb87ea8d4. +// +// Solidity: function disburseFees() returns() +func (_FeeSplitter *FeeSplitterTransactorSession) DisburseFees() (*types.Transaction, error) { + return _FeeSplitter.Contract.DisburseFees(&_FeeSplitter.TransactOpts) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address _sharesCalculator) returns() +func (_FeeSplitter *FeeSplitterTransactor) Initialize(opts *bind.TransactOpts, _sharesCalculator common.Address) (*types.Transaction, error) { + return _FeeSplitter.contract.Transact(opts, "initialize", _sharesCalculator) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address _sharesCalculator) returns() +func (_FeeSplitter *FeeSplitterSession) Initialize(_sharesCalculator common.Address) (*types.Transaction, error) { + return _FeeSplitter.Contract.Initialize(&_FeeSplitter.TransactOpts, _sharesCalculator) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address _sharesCalculator) returns() +func (_FeeSplitter *FeeSplitterTransactorSession) Initialize(_sharesCalculator common.Address) (*types.Transaction, error) { + return _FeeSplitter.Contract.Initialize(&_FeeSplitter.TransactOpts, _sharesCalculator) +} + +// SetFeeDisbursementInterval is a paid mutator transaction binding the contract method 0x7fc81bb7. +// +// Solidity: function setFeeDisbursementInterval(uint128 _newFeeDisbursementInterval) returns() +func (_FeeSplitter *FeeSplitterTransactor) SetFeeDisbursementInterval(opts *bind.TransactOpts, _newFeeDisbursementInterval *big.Int) (*types.Transaction, error) { + return _FeeSplitter.contract.Transact(opts, "setFeeDisbursementInterval", _newFeeDisbursementInterval) +} + +// SetFeeDisbursementInterval is a paid mutator transaction binding the contract method 0x7fc81bb7. +// +// Solidity: function setFeeDisbursementInterval(uint128 _newFeeDisbursementInterval) returns() +func (_FeeSplitter *FeeSplitterSession) SetFeeDisbursementInterval(_newFeeDisbursementInterval *big.Int) (*types.Transaction, error) { + return _FeeSplitter.Contract.SetFeeDisbursementInterval(&_FeeSplitter.TransactOpts, _newFeeDisbursementInterval) +} + +// SetFeeDisbursementInterval is a paid mutator transaction binding the contract method 0x7fc81bb7. +// +// Solidity: function setFeeDisbursementInterval(uint128 _newFeeDisbursementInterval) returns() +func (_FeeSplitter *FeeSplitterTransactorSession) SetFeeDisbursementInterval(_newFeeDisbursementInterval *big.Int) (*types.Transaction, error) { + return _FeeSplitter.Contract.SetFeeDisbursementInterval(&_FeeSplitter.TransactOpts, _newFeeDisbursementInterval) +} + +// SetSharesCalculator is a paid mutator transaction binding the contract method 0x0a7617b3. +// +// Solidity: function setSharesCalculator(address _newSharesCalculator) returns() +func (_FeeSplitter *FeeSplitterTransactor) SetSharesCalculator(opts *bind.TransactOpts, _newSharesCalculator common.Address) (*types.Transaction, error) { + return _FeeSplitter.contract.Transact(opts, "setSharesCalculator", _newSharesCalculator) +} + +// SetSharesCalculator is a paid mutator transaction binding the contract method 0x0a7617b3. +// +// Solidity: function setSharesCalculator(address _newSharesCalculator) returns() +func (_FeeSplitter *FeeSplitterSession) SetSharesCalculator(_newSharesCalculator common.Address) (*types.Transaction, error) { + return _FeeSplitter.Contract.SetSharesCalculator(&_FeeSplitter.TransactOpts, _newSharesCalculator) +} + +// SetSharesCalculator is a paid mutator transaction binding the contract method 0x0a7617b3. +// +// Solidity: function setSharesCalculator(address _newSharesCalculator) returns() +func (_FeeSplitter *FeeSplitterTransactorSession) SetSharesCalculator(_newSharesCalculator common.Address) (*types.Transaction, error) { + return _FeeSplitter.Contract.SetSharesCalculator(&_FeeSplitter.TransactOpts, _newSharesCalculator) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_FeeSplitter *FeeSplitterTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FeeSplitter.contract.RawTransact(opts, nil) // calldata is disallowed for receive function +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_FeeSplitter *FeeSplitterSession) Receive() (*types.Transaction, error) { + return _FeeSplitter.Contract.Receive(&_FeeSplitter.TransactOpts) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_FeeSplitter *FeeSplitterTransactorSession) Receive() (*types.Transaction, error) { + return _FeeSplitter.Contract.Receive(&_FeeSplitter.TransactOpts) +} + +// FeeSplitterFeeDisbursementIntervalUpdatedIterator is returned from FilterFeeDisbursementIntervalUpdated and is used to iterate over the raw logs and unpacked data for FeeDisbursementIntervalUpdated events raised by the FeeSplitter contract. +type FeeSplitterFeeDisbursementIntervalUpdatedIterator struct { + Event *FeeSplitterFeeDisbursementIntervalUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FeeSplitterFeeDisbursementIntervalUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeSplitterFeeDisbursementIntervalUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FeeSplitterFeeDisbursementIntervalUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FeeSplitterFeeDisbursementIntervalUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FeeSplitterFeeDisbursementIntervalUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FeeSplitterFeeDisbursementIntervalUpdated represents a FeeDisbursementIntervalUpdated event raised by the FeeSplitter contract. +type FeeSplitterFeeDisbursementIntervalUpdated struct { + OldFeeDisbursementInterval *big.Int + NewFeeDisbursementInterval *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeDisbursementIntervalUpdated is a free log retrieval operation binding the contract event 0x4492086b630ed3846eec0979dd87a71c814ceb1c6dab80ab81e3450b21e4de28. +// +// Solidity: event FeeDisbursementIntervalUpdated(uint128 oldFeeDisbursementInterval, uint128 newFeeDisbursementInterval) +func (_FeeSplitter *FeeSplitterFilterer) FilterFeeDisbursementIntervalUpdated(opts *bind.FilterOpts) (*FeeSplitterFeeDisbursementIntervalUpdatedIterator, error) { + + logs, sub, err := _FeeSplitter.contract.FilterLogs(opts, "FeeDisbursementIntervalUpdated") + if err != nil { + return nil, err + } + return &FeeSplitterFeeDisbursementIntervalUpdatedIterator{contract: _FeeSplitter.contract, event: "FeeDisbursementIntervalUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeDisbursementIntervalUpdated is a free log subscription operation binding the contract event 0x4492086b630ed3846eec0979dd87a71c814ceb1c6dab80ab81e3450b21e4de28. +// +// Solidity: event FeeDisbursementIntervalUpdated(uint128 oldFeeDisbursementInterval, uint128 newFeeDisbursementInterval) +func (_FeeSplitter *FeeSplitterFilterer) WatchFeeDisbursementIntervalUpdated(opts *bind.WatchOpts, sink chan<- *FeeSplitterFeeDisbursementIntervalUpdated) (event.Subscription, error) { + + logs, sub, err := _FeeSplitter.contract.WatchLogs(opts, "FeeDisbursementIntervalUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FeeSplitterFeeDisbursementIntervalUpdated) + if err := _FeeSplitter.contract.UnpackLog(event, "FeeDisbursementIntervalUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeDisbursementIntervalUpdated is a log parse operation binding the contract event 0x4492086b630ed3846eec0979dd87a71c814ceb1c6dab80ab81e3450b21e4de28. +// +// Solidity: event FeeDisbursementIntervalUpdated(uint128 oldFeeDisbursementInterval, uint128 newFeeDisbursementInterval) +func (_FeeSplitter *FeeSplitterFilterer) ParseFeeDisbursementIntervalUpdated(log types.Log) (*FeeSplitterFeeDisbursementIntervalUpdated, error) { + event := new(FeeSplitterFeeDisbursementIntervalUpdated) + if err := _FeeSplitter.contract.UnpackLog(event, "FeeDisbursementIntervalUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FeeSplitterFeesDisbursedIterator is returned from FilterFeesDisbursed and is used to iterate over the raw logs and unpacked data for FeesDisbursed events raised by the FeeSplitter contract. +type FeeSplitterFeesDisbursedIterator struct { + Event *FeeSplitterFeesDisbursed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FeeSplitterFeesDisbursedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeSplitterFeesDisbursed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FeeSplitterFeesDisbursed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FeeSplitterFeesDisbursedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FeeSplitterFeesDisbursedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FeeSplitterFeesDisbursed represents a FeesDisbursed event raised by the FeeSplitter contract. +type FeeSplitterFeesDisbursed struct { + ShareInfo []ISharesCalculatorShareInfo + GrossRevenue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesDisbursed is a free log retrieval operation binding the contract event 0x73f9a13241a1848ec157967f3a85601709353e616f1f2605d818c0f2d21774df. +// +// Solidity: event FeesDisbursed((address,uint256)[] shareInfo, uint256 grossRevenue) +func (_FeeSplitter *FeeSplitterFilterer) FilterFeesDisbursed(opts *bind.FilterOpts) (*FeeSplitterFeesDisbursedIterator, error) { + + logs, sub, err := _FeeSplitter.contract.FilterLogs(opts, "FeesDisbursed") + if err != nil { + return nil, err + } + return &FeeSplitterFeesDisbursedIterator{contract: _FeeSplitter.contract, event: "FeesDisbursed", logs: logs, sub: sub}, nil +} + +// WatchFeesDisbursed is a free log subscription operation binding the contract event 0x73f9a13241a1848ec157967f3a85601709353e616f1f2605d818c0f2d21774df. +// +// Solidity: event FeesDisbursed((address,uint256)[] shareInfo, uint256 grossRevenue) +func (_FeeSplitter *FeeSplitterFilterer) WatchFeesDisbursed(opts *bind.WatchOpts, sink chan<- *FeeSplitterFeesDisbursed) (event.Subscription, error) { + + logs, sub, err := _FeeSplitter.contract.WatchLogs(opts, "FeesDisbursed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FeeSplitterFeesDisbursed) + if err := _FeeSplitter.contract.UnpackLog(event, "FeesDisbursed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesDisbursed is a log parse operation binding the contract event 0x73f9a13241a1848ec157967f3a85601709353e616f1f2605d818c0f2d21774df. +// +// Solidity: event FeesDisbursed((address,uint256)[] shareInfo, uint256 grossRevenue) +func (_FeeSplitter *FeeSplitterFilterer) ParseFeesDisbursed(log types.Log) (*FeeSplitterFeesDisbursed, error) { + event := new(FeeSplitterFeesDisbursed) + if err := _FeeSplitter.contract.UnpackLog(event, "FeesDisbursed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FeeSplitterFeesReceivedIterator is returned from FilterFeesReceived and is used to iterate over the raw logs and unpacked data for FeesReceived events raised by the FeeSplitter contract. +type FeeSplitterFeesReceivedIterator struct { + Event *FeeSplitterFeesReceived // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FeeSplitterFeesReceivedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeSplitterFeesReceived) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FeeSplitterFeesReceived) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FeeSplitterFeesReceivedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FeeSplitterFeesReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FeeSplitterFeesReceived represents a FeesReceived event raised by the FeeSplitter contract. +type FeeSplitterFeesReceived struct { + Sender common.Address + Amount *big.Int + NewBalance *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesReceived is a free log retrieval operation binding the contract event 0x213e72af0d3613bd643cff3059f872c1015e6541624e37872bf95eefbaf220a8. +// +// Solidity: event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance) +func (_FeeSplitter *FeeSplitterFilterer) FilterFeesReceived(opts *bind.FilterOpts, sender []common.Address) (*FeeSplitterFeesReceivedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FeeSplitter.contract.FilterLogs(opts, "FeesReceived", senderRule) + if err != nil { + return nil, err + } + return &FeeSplitterFeesReceivedIterator{contract: _FeeSplitter.contract, event: "FeesReceived", logs: logs, sub: sub}, nil +} + +// WatchFeesReceived is a free log subscription operation binding the contract event 0x213e72af0d3613bd643cff3059f872c1015e6541624e37872bf95eefbaf220a8. +// +// Solidity: event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance) +func (_FeeSplitter *FeeSplitterFilterer) WatchFeesReceived(opts *bind.WatchOpts, sink chan<- *FeeSplitterFeesReceived, sender []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FeeSplitter.contract.WatchLogs(opts, "FeesReceived", senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FeeSplitterFeesReceived) + if err := _FeeSplitter.contract.UnpackLog(event, "FeesReceived", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesReceived is a log parse operation binding the contract event 0x213e72af0d3613bd643cff3059f872c1015e6541624e37872bf95eefbaf220a8. +// +// Solidity: event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance) +func (_FeeSplitter *FeeSplitterFilterer) ParseFeesReceived(log types.Log) (*FeeSplitterFeesReceived, error) { + event := new(FeeSplitterFeesReceived) + if err := _FeeSplitter.contract.UnpackLog(event, "FeesReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FeeSplitterInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the FeeSplitter contract. +type FeeSplitterInitializedIterator struct { + Event *FeeSplitterInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FeeSplitterInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeSplitterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FeeSplitterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FeeSplitterInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FeeSplitterInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FeeSplitterInitialized represents a Initialized event raised by the FeeSplitter contract. +type FeeSplitterInitialized struct { + Version uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_FeeSplitter *FeeSplitterFilterer) FilterInitialized(opts *bind.FilterOpts) (*FeeSplitterInitializedIterator, error) { + + logs, sub, err := _FeeSplitter.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &FeeSplitterInitializedIterator{contract: _FeeSplitter.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_FeeSplitter *FeeSplitterFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *FeeSplitterInitialized) (event.Subscription, error) { + + logs, sub, err := _FeeSplitter.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FeeSplitterInitialized) + if err := _FeeSplitter.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_FeeSplitter *FeeSplitterFilterer) ParseInitialized(log types.Log) (*FeeSplitterInitialized, error) { + event := new(FeeSplitterInitialized) + if err := _FeeSplitter.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FeeSplitterSharesCalculatorUpdatedIterator is returned from FilterSharesCalculatorUpdated and is used to iterate over the raw logs and unpacked data for SharesCalculatorUpdated events raised by the FeeSplitter contract. +type FeeSplitterSharesCalculatorUpdatedIterator struct { + Event *FeeSplitterSharesCalculatorUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FeeSplitterSharesCalculatorUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeSplitterSharesCalculatorUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FeeSplitterSharesCalculatorUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FeeSplitterSharesCalculatorUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FeeSplitterSharesCalculatorUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FeeSplitterSharesCalculatorUpdated represents a SharesCalculatorUpdated event raised by the FeeSplitter contract. +type FeeSplitterSharesCalculatorUpdated struct { + OldSharesCalculator common.Address + NewSharesCalculator common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSharesCalculatorUpdated is a free log retrieval operation binding the contract event 0x16417cc372deec0caee5f52e2ad77a5f07b4591fd56b4ff31b6e20f817d4daeb. +// +// Solidity: event SharesCalculatorUpdated(address oldSharesCalculator, address newSharesCalculator) +func (_FeeSplitter *FeeSplitterFilterer) FilterSharesCalculatorUpdated(opts *bind.FilterOpts) (*FeeSplitterSharesCalculatorUpdatedIterator, error) { + + logs, sub, err := _FeeSplitter.contract.FilterLogs(opts, "SharesCalculatorUpdated") + if err != nil { + return nil, err + } + return &FeeSplitterSharesCalculatorUpdatedIterator{contract: _FeeSplitter.contract, event: "SharesCalculatorUpdated", logs: logs, sub: sub}, nil +} + +// WatchSharesCalculatorUpdated is a free log subscription operation binding the contract event 0x16417cc372deec0caee5f52e2ad77a5f07b4591fd56b4ff31b6e20f817d4daeb. +// +// Solidity: event SharesCalculatorUpdated(address oldSharesCalculator, address newSharesCalculator) +func (_FeeSplitter *FeeSplitterFilterer) WatchSharesCalculatorUpdated(opts *bind.WatchOpts, sink chan<- *FeeSplitterSharesCalculatorUpdated) (event.Subscription, error) { + + logs, sub, err := _FeeSplitter.contract.WatchLogs(opts, "SharesCalculatorUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FeeSplitterSharesCalculatorUpdated) + if err := _FeeSplitter.contract.UnpackLog(event, "SharesCalculatorUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSharesCalculatorUpdated is a log parse operation binding the contract event 0x16417cc372deec0caee5f52e2ad77a5f07b4591fd56b4ff31b6e20f817d4daeb. +// +// Solidity: event SharesCalculatorUpdated(address oldSharesCalculator, address newSharesCalculator) +func (_FeeSplitter *FeeSplitterFilterer) ParseSharesCalculatorUpdated(log types.Log) (*FeeSplitterSharesCalculatorUpdated, error) { + event := new(FeeSplitterSharesCalculatorUpdated) + if err := _FeeSplitter.contract.UnpackLog(event, "SharesCalculatorUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/op-e2e/bindings/operatorfeevault.go b/op-e2e/bindings/operatorfeevault.go new file mode 100644 index 00000000000..83485a6ff48 --- /dev/null +++ b/op-e2e/bindings/operatorfeevault.go @@ -0,0 +1,1389 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// OperatorFeeVaultMetaData contains all meta data concerning the OperatorFeeVault contract. +var OperatorFeeVaultMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"MIN_WITHDRAWAL_AMOUNT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"RECIPIENT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"WITHDRAWAL_NETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_minWithdrawalAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_withdrawalNetwork\",\"type\":\"uint8\",\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"minWithdrawalAmount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recipient\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setMinWithdrawalAmount\",\"inputs\":[{\"name\":\"_newMinWithdrawalAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRecipient\",\"inputs\":[{\"name\":\"_newRecipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setWithdrawalNetwork\",\"inputs\":[{\"name\":\"_newWithdrawalNetwork\",\"type\":\"uint8\",\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"totalProcessed\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[],\"outputs\":[{\"name\":\"value_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawalNetwork\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinWithdrawalAmountUpdated\",\"inputs\":[{\"name\":\"oldWithdrawalAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newWithdrawalAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RecipientUpdated\",\"inputs\":[{\"name\":\"oldRecipient\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newRecipient\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Withdrawal\",\"inputs\":[{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"from\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Withdrawal\",\"inputs\":[{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"from\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalNetwork\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalNetworkUpdated\",\"inputs\":[{\"name\":\"oldWithdrawalNetwork\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumTypes.WithdrawalNetwork\"},{\"name\":\"newWithdrawalNetwork\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"FeeVault_OnlyProxyAdminOwner\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]}]", + Bin: "0x6080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b610eb9806100d65f395ff3fe6080604052600436106100d1575f3560e01c806382356d8a1161007c57806385b5b14d1161005757806385b5b14d14610276578063b49dc74114610295578063d0e12f90146102b4578063d3e5792b146102e3575f80fd5b806382356d8a1461020f5780638312f1491461024d57806384411d6514610262575f80fd5b80633ccfd60b116100ac5780633ccfd60b1461016c57806354fd4d501461018e57806366d003ac146101e3575f80fd5b80630d9019e1146100dc578063307f29621461012c5780633bbed4a01461014d575f80fd5b366100d857005b5f80fd5b3480156100e7575f80fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610137575f80fd5b5061014b610146366004610c86565b6102f7565b005b348015610158575f80fd5b5061014b610167366004610cc3565b61047a565b348015610177575f80fd5b506101806105de565b604051908152602001610123565b348015610199575f80fd5b506101d66040518060400160405280600581526020017f312e312e3000000000000000000000000000000000000000000000000000000081525081565b6040516101239190610cde565b3480156101ee575f80fd5b506002546101029073ffffffffffffffffffffffffffffffffffffffff1681565b34801561021a575f80fd5b506002546102409074010000000000000000000000000000000000000000900460ff1681565b6040516101239190610d97565b348015610258575f80fd5b5061018060015481565b34801561026d575f80fd5b506101805f5481565b348015610281575f80fd5b5061014b610290366004610dab565b610918565b3480156102a0575f80fd5b5061014b6102af366004610dc2565b610a3b565b3480156102bf575f80fd5b5060025474010000000000000000000000000000000000000000900460ff16610240565b3480156102ee575f80fd5b50600154610180565b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610354573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103789190610dfd565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103dc576040517f7cd7e09f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547401000000000000000000000000000000000000000080820460ff1692849290917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091169083600181111561043857610438610d31565b02179055507ff2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc8818360405161046e929190610e18565b60405180910390a15050565b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104fb9190610dfd565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461055f576040517f7cd7e09f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e4593910161046e565b5f60015447101561069c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f4665655661756c743a207769746864726177616c20616d6f756e74206d75737460448201527f2062652067726561746572207468616e206d696e696d756d207769746864726160648201527f77616c20616d6f756e7400000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b479050805f808282546106af9190610e33565b90915550506002546040805183815273ffffffffffffffffffffffffffffffffffffffff90921660208301523382820152517fc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba9181900360600190a16002546040517f38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee9161077491849173ffffffffffffffffffffffffffffffffffffffff811691339174010000000000000000000000000000000000000000900460ff1690610e6b565b60405180910390a1600160025474010000000000000000000000000000000000000000900460ff1660018111156107ad576107ad610d31565b0361086a576002545f906107d79073ffffffffffffffffffffffffffffffffffffffff1683610c4f565b905080610866576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4665655661756c743a206661696c656420746f2073656e642045544820746f2060448201527f4c322066656520726563697069656e74000000000000000000000000000000006064820152608401610693565b5090565b6002546040517fc2b3e5ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015262061a806024820152606060448201525f60648201527342000000000000000000000000000000000000169063c2b3e5ac9083906084015f604051808303818588803b1580156108fe575f80fd5b505af1158015610910573d5f803e3d5ffd5b505050505090565b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610975573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109999190610dfd565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109fd576040517f7cd7e09f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180549082905560408051828152602081018490527f895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e4203910161046e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610a855750825b90505f8267ffffffffffffffff166001148015610aa15750303b155b905081158015610aaf575080155b15610ae6576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610b475784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b6002805473ffffffffffffffffffffffffffffffffffffffff8a167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117835560018a81558993927fffffffffffffffffffffff000000000000000000000000000000000000000000169091179074010000000000000000000000000000000000000000908490811115610bdf57610bdf610d31565b02179055508315610c455784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b5f610c5b835a84610c62565b9392505050565b5f805f805f858888f1949350505050565b803560028110610c81575f80fd5b919050565b5f60208284031215610c96575f80fd5b610c5b82610c73565b73ffffffffffffffffffffffffffffffffffffffff81168114610cc0575f80fd5b50565b5f60208284031215610cd3575f80fd5b8135610c5b81610c9f565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60028110610d93577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610da58284610d5e565b92915050565b5f60208284031215610dbb575f80fd5b5035919050565b5f805f60608486031215610dd4575f80fd5b8335610ddf81610c9f565b925060208401359150610df460408501610c73565b90509250925092565b5f60208284031215610e0d575f80fd5b8151610c5b81610c9f565b60408101610e268285610d5e565b610c5b6020830184610d5e565b80820180821115610da5577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b84815273ffffffffffffffffffffffffffffffffffffffff84811660208301528316604082015260808101610ea36060830184610d5e565b9594505050505056fea164736f6c6343000819000a", +} + +// OperatorFeeVaultABI is the input ABI used to generate the binding from. +// Deprecated: Use OperatorFeeVaultMetaData.ABI instead. +var OperatorFeeVaultABI = OperatorFeeVaultMetaData.ABI + +// OperatorFeeVaultBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use OperatorFeeVaultMetaData.Bin instead. +var OperatorFeeVaultBin = OperatorFeeVaultMetaData.Bin + +// DeployOperatorFeeVault deploys a new Ethereum contract, binding an instance of OperatorFeeVault to it. +func DeployOperatorFeeVault(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *OperatorFeeVault, error) { + parsed, err := OperatorFeeVaultMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(OperatorFeeVaultBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &OperatorFeeVault{OperatorFeeVaultCaller: OperatorFeeVaultCaller{contract: contract}, OperatorFeeVaultTransactor: OperatorFeeVaultTransactor{contract: contract}, OperatorFeeVaultFilterer: OperatorFeeVaultFilterer{contract: contract}}, nil +} + +// OperatorFeeVault is an auto generated Go binding around an Ethereum contract. +type OperatorFeeVault struct { + OperatorFeeVaultCaller // Read-only binding to the contract + OperatorFeeVaultTransactor // Write-only binding to the contract + OperatorFeeVaultFilterer // Log filterer for contract events +} + +// OperatorFeeVaultCaller is an auto generated read-only Go binding around an Ethereum contract. +type OperatorFeeVaultCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OperatorFeeVaultTransactor is an auto generated write-only Go binding around an Ethereum contract. +type OperatorFeeVaultTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OperatorFeeVaultFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type OperatorFeeVaultFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OperatorFeeVaultSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type OperatorFeeVaultSession struct { + Contract *OperatorFeeVault // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// OperatorFeeVaultCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type OperatorFeeVaultCallerSession struct { + Contract *OperatorFeeVaultCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// OperatorFeeVaultTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type OperatorFeeVaultTransactorSession struct { + Contract *OperatorFeeVaultTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// OperatorFeeVaultRaw is an auto generated low-level Go binding around an Ethereum contract. +type OperatorFeeVaultRaw struct { + Contract *OperatorFeeVault // Generic contract binding to access the raw methods on +} + +// OperatorFeeVaultCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type OperatorFeeVaultCallerRaw struct { + Contract *OperatorFeeVaultCaller // Generic read-only contract binding to access the raw methods on +} + +// OperatorFeeVaultTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type OperatorFeeVaultTransactorRaw struct { + Contract *OperatorFeeVaultTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewOperatorFeeVault creates a new instance of OperatorFeeVault, bound to a specific deployed contract. +func NewOperatorFeeVault(address common.Address, backend bind.ContractBackend) (*OperatorFeeVault, error) { + contract, err := bindOperatorFeeVault(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &OperatorFeeVault{OperatorFeeVaultCaller: OperatorFeeVaultCaller{contract: contract}, OperatorFeeVaultTransactor: OperatorFeeVaultTransactor{contract: contract}, OperatorFeeVaultFilterer: OperatorFeeVaultFilterer{contract: contract}}, nil +} + +// NewOperatorFeeVaultCaller creates a new read-only instance of OperatorFeeVault, bound to a specific deployed contract. +func NewOperatorFeeVaultCaller(address common.Address, caller bind.ContractCaller) (*OperatorFeeVaultCaller, error) { + contract, err := bindOperatorFeeVault(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &OperatorFeeVaultCaller{contract: contract}, nil +} + +// NewOperatorFeeVaultTransactor creates a new write-only instance of OperatorFeeVault, bound to a specific deployed contract. +func NewOperatorFeeVaultTransactor(address common.Address, transactor bind.ContractTransactor) (*OperatorFeeVaultTransactor, error) { + contract, err := bindOperatorFeeVault(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &OperatorFeeVaultTransactor{contract: contract}, nil +} + +// NewOperatorFeeVaultFilterer creates a new log filterer instance of OperatorFeeVault, bound to a specific deployed contract. +func NewOperatorFeeVaultFilterer(address common.Address, filterer bind.ContractFilterer) (*OperatorFeeVaultFilterer, error) { + contract, err := bindOperatorFeeVault(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &OperatorFeeVaultFilterer{contract: contract}, nil +} + +// bindOperatorFeeVault binds a generic wrapper to an already deployed contract. +func bindOperatorFeeVault(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := OperatorFeeVaultMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_OperatorFeeVault *OperatorFeeVaultRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _OperatorFeeVault.Contract.OperatorFeeVaultCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_OperatorFeeVault *OperatorFeeVaultRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.OperatorFeeVaultTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_OperatorFeeVault *OperatorFeeVaultRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.OperatorFeeVaultTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_OperatorFeeVault *OperatorFeeVaultCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _OperatorFeeVault.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_OperatorFeeVault *OperatorFeeVaultTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_OperatorFeeVault *OperatorFeeVaultTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.contract.Transact(opts, method, params...) +} + +// MINWITHDRAWALAMOUNT is a free data retrieval call binding the contract method 0xd3e5792b. +// +// Solidity: function MIN_WITHDRAWAL_AMOUNT() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultCaller) MINWITHDRAWALAMOUNT(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "MIN_WITHDRAWAL_AMOUNT") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MINWITHDRAWALAMOUNT is a free data retrieval call binding the contract method 0xd3e5792b. +// +// Solidity: function MIN_WITHDRAWAL_AMOUNT() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultSession) MINWITHDRAWALAMOUNT() (*big.Int, error) { + return _OperatorFeeVault.Contract.MINWITHDRAWALAMOUNT(&_OperatorFeeVault.CallOpts) +} + +// MINWITHDRAWALAMOUNT is a free data retrieval call binding the contract method 0xd3e5792b. +// +// Solidity: function MIN_WITHDRAWAL_AMOUNT() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) MINWITHDRAWALAMOUNT() (*big.Int, error) { + return _OperatorFeeVault.Contract.MINWITHDRAWALAMOUNT(&_OperatorFeeVault.CallOpts) +} + +// RECIPIENT is a free data retrieval call binding the contract method 0x0d9019e1. +// +// Solidity: function RECIPIENT() view returns(address) +func (_OperatorFeeVault *OperatorFeeVaultCaller) RECIPIENT(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "RECIPIENT") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RECIPIENT is a free data retrieval call binding the contract method 0x0d9019e1. +// +// Solidity: function RECIPIENT() view returns(address) +func (_OperatorFeeVault *OperatorFeeVaultSession) RECIPIENT() (common.Address, error) { + return _OperatorFeeVault.Contract.RECIPIENT(&_OperatorFeeVault.CallOpts) +} + +// RECIPIENT is a free data retrieval call binding the contract method 0x0d9019e1. +// +// Solidity: function RECIPIENT() view returns(address) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) RECIPIENT() (common.Address, error) { + return _OperatorFeeVault.Contract.RECIPIENT(&_OperatorFeeVault.CallOpts) +} + +// WITHDRAWALNETWORK is a free data retrieval call binding the contract method 0xd0e12f90. +// +// Solidity: function WITHDRAWAL_NETWORK() view returns(uint8) +func (_OperatorFeeVault *OperatorFeeVaultCaller) WITHDRAWALNETWORK(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "WITHDRAWAL_NETWORK") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// WITHDRAWALNETWORK is a free data retrieval call binding the contract method 0xd0e12f90. +// +// Solidity: function WITHDRAWAL_NETWORK() view returns(uint8) +func (_OperatorFeeVault *OperatorFeeVaultSession) WITHDRAWALNETWORK() (uint8, error) { + return _OperatorFeeVault.Contract.WITHDRAWALNETWORK(&_OperatorFeeVault.CallOpts) +} + +// WITHDRAWALNETWORK is a free data retrieval call binding the contract method 0xd0e12f90. +// +// Solidity: function WITHDRAWAL_NETWORK() view returns(uint8) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) WITHDRAWALNETWORK() (uint8, error) { + return _OperatorFeeVault.Contract.WITHDRAWALNETWORK(&_OperatorFeeVault.CallOpts) +} + +// MinWithdrawalAmount is a free data retrieval call binding the contract method 0x8312f149. +// +// Solidity: function minWithdrawalAmount() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultCaller) MinWithdrawalAmount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "minWithdrawalAmount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MinWithdrawalAmount is a free data retrieval call binding the contract method 0x8312f149. +// +// Solidity: function minWithdrawalAmount() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultSession) MinWithdrawalAmount() (*big.Int, error) { + return _OperatorFeeVault.Contract.MinWithdrawalAmount(&_OperatorFeeVault.CallOpts) +} + +// MinWithdrawalAmount is a free data retrieval call binding the contract method 0x8312f149. +// +// Solidity: function minWithdrawalAmount() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) MinWithdrawalAmount() (*big.Int, error) { + return _OperatorFeeVault.Contract.MinWithdrawalAmount(&_OperatorFeeVault.CallOpts) +} + +// Recipient is a free data retrieval call binding the contract method 0x66d003ac. +// +// Solidity: function recipient() view returns(address) +func (_OperatorFeeVault *OperatorFeeVaultCaller) Recipient(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "recipient") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Recipient is a free data retrieval call binding the contract method 0x66d003ac. +// +// Solidity: function recipient() view returns(address) +func (_OperatorFeeVault *OperatorFeeVaultSession) Recipient() (common.Address, error) { + return _OperatorFeeVault.Contract.Recipient(&_OperatorFeeVault.CallOpts) +} + +// Recipient is a free data retrieval call binding the contract method 0x66d003ac. +// +// Solidity: function recipient() view returns(address) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) Recipient() (common.Address, error) { + return _OperatorFeeVault.Contract.Recipient(&_OperatorFeeVault.CallOpts) +} + +// TotalProcessed is a free data retrieval call binding the contract method 0x84411d65. +// +// Solidity: function totalProcessed() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultCaller) TotalProcessed(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "totalProcessed") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalProcessed is a free data retrieval call binding the contract method 0x84411d65. +// +// Solidity: function totalProcessed() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultSession) TotalProcessed() (*big.Int, error) { + return _OperatorFeeVault.Contract.TotalProcessed(&_OperatorFeeVault.CallOpts) +} + +// TotalProcessed is a free data retrieval call binding the contract method 0x84411d65. +// +// Solidity: function totalProcessed() view returns(uint256) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) TotalProcessed() (*big.Int, error) { + return _OperatorFeeVault.Contract.TotalProcessed(&_OperatorFeeVault.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_OperatorFeeVault *OperatorFeeVaultCaller) Version(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "version") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_OperatorFeeVault *OperatorFeeVaultSession) Version() (string, error) { + return _OperatorFeeVault.Contract.Version(&_OperatorFeeVault.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) Version() (string, error) { + return _OperatorFeeVault.Contract.Version(&_OperatorFeeVault.CallOpts) +} + +// WithdrawalNetwork is a free data retrieval call binding the contract method 0x82356d8a. +// +// Solidity: function withdrawalNetwork() view returns(uint8) +func (_OperatorFeeVault *OperatorFeeVaultCaller) WithdrawalNetwork(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _OperatorFeeVault.contract.Call(opts, &out, "withdrawalNetwork") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// WithdrawalNetwork is a free data retrieval call binding the contract method 0x82356d8a. +// +// Solidity: function withdrawalNetwork() view returns(uint8) +func (_OperatorFeeVault *OperatorFeeVaultSession) WithdrawalNetwork() (uint8, error) { + return _OperatorFeeVault.Contract.WithdrawalNetwork(&_OperatorFeeVault.CallOpts) +} + +// WithdrawalNetwork is a free data retrieval call binding the contract method 0x82356d8a. +// +// Solidity: function withdrawalNetwork() view returns(uint8) +func (_OperatorFeeVault *OperatorFeeVaultCallerSession) WithdrawalNetwork() (uint8, error) { + return _OperatorFeeVault.Contract.WithdrawalNetwork(&_OperatorFeeVault.CallOpts) +} + +// Initialize is a paid mutator transaction binding the contract method 0xb49dc741. +// +// Solidity: function initialize(address _recipient, uint256 _minWithdrawalAmount, uint8 _withdrawalNetwork) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactor) Initialize(opts *bind.TransactOpts, _recipient common.Address, _minWithdrawalAmount *big.Int, _withdrawalNetwork uint8) (*types.Transaction, error) { + return _OperatorFeeVault.contract.Transact(opts, "initialize", _recipient, _minWithdrawalAmount, _withdrawalNetwork) +} + +// Initialize is a paid mutator transaction binding the contract method 0xb49dc741. +// +// Solidity: function initialize(address _recipient, uint256 _minWithdrawalAmount, uint8 _withdrawalNetwork) returns() +func (_OperatorFeeVault *OperatorFeeVaultSession) Initialize(_recipient common.Address, _minWithdrawalAmount *big.Int, _withdrawalNetwork uint8) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.Initialize(&_OperatorFeeVault.TransactOpts, _recipient, _minWithdrawalAmount, _withdrawalNetwork) +} + +// Initialize is a paid mutator transaction binding the contract method 0xb49dc741. +// +// Solidity: function initialize(address _recipient, uint256 _minWithdrawalAmount, uint8 _withdrawalNetwork) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactorSession) Initialize(_recipient common.Address, _minWithdrawalAmount *big.Int, _withdrawalNetwork uint8) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.Initialize(&_OperatorFeeVault.TransactOpts, _recipient, _minWithdrawalAmount, _withdrawalNetwork) +} + +// SetMinWithdrawalAmount is a paid mutator transaction binding the contract method 0x85b5b14d. +// +// Solidity: function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactor) SetMinWithdrawalAmount(opts *bind.TransactOpts, _newMinWithdrawalAmount *big.Int) (*types.Transaction, error) { + return _OperatorFeeVault.contract.Transact(opts, "setMinWithdrawalAmount", _newMinWithdrawalAmount) +} + +// SetMinWithdrawalAmount is a paid mutator transaction binding the contract method 0x85b5b14d. +// +// Solidity: function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) returns() +func (_OperatorFeeVault *OperatorFeeVaultSession) SetMinWithdrawalAmount(_newMinWithdrawalAmount *big.Int) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.SetMinWithdrawalAmount(&_OperatorFeeVault.TransactOpts, _newMinWithdrawalAmount) +} + +// SetMinWithdrawalAmount is a paid mutator transaction binding the contract method 0x85b5b14d. +// +// Solidity: function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactorSession) SetMinWithdrawalAmount(_newMinWithdrawalAmount *big.Int) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.SetMinWithdrawalAmount(&_OperatorFeeVault.TransactOpts, _newMinWithdrawalAmount) +} + +// SetRecipient is a paid mutator transaction binding the contract method 0x3bbed4a0. +// +// Solidity: function setRecipient(address _newRecipient) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactor) SetRecipient(opts *bind.TransactOpts, _newRecipient common.Address) (*types.Transaction, error) { + return _OperatorFeeVault.contract.Transact(opts, "setRecipient", _newRecipient) +} + +// SetRecipient is a paid mutator transaction binding the contract method 0x3bbed4a0. +// +// Solidity: function setRecipient(address _newRecipient) returns() +func (_OperatorFeeVault *OperatorFeeVaultSession) SetRecipient(_newRecipient common.Address) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.SetRecipient(&_OperatorFeeVault.TransactOpts, _newRecipient) +} + +// SetRecipient is a paid mutator transaction binding the contract method 0x3bbed4a0. +// +// Solidity: function setRecipient(address _newRecipient) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactorSession) SetRecipient(_newRecipient common.Address) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.SetRecipient(&_OperatorFeeVault.TransactOpts, _newRecipient) +} + +// SetWithdrawalNetwork is a paid mutator transaction binding the contract method 0x307f2962. +// +// Solidity: function setWithdrawalNetwork(uint8 _newWithdrawalNetwork) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactor) SetWithdrawalNetwork(opts *bind.TransactOpts, _newWithdrawalNetwork uint8) (*types.Transaction, error) { + return _OperatorFeeVault.contract.Transact(opts, "setWithdrawalNetwork", _newWithdrawalNetwork) +} + +// SetWithdrawalNetwork is a paid mutator transaction binding the contract method 0x307f2962. +// +// Solidity: function setWithdrawalNetwork(uint8 _newWithdrawalNetwork) returns() +func (_OperatorFeeVault *OperatorFeeVaultSession) SetWithdrawalNetwork(_newWithdrawalNetwork uint8) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.SetWithdrawalNetwork(&_OperatorFeeVault.TransactOpts, _newWithdrawalNetwork) +} + +// SetWithdrawalNetwork is a paid mutator transaction binding the contract method 0x307f2962. +// +// Solidity: function setWithdrawalNetwork(uint8 _newWithdrawalNetwork) returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactorSession) SetWithdrawalNetwork(_newWithdrawalNetwork uint8) (*types.Transaction, error) { + return _OperatorFeeVault.Contract.SetWithdrawalNetwork(&_OperatorFeeVault.TransactOpts, _newWithdrawalNetwork) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns(uint256 value_) +func (_OperatorFeeVault *OperatorFeeVaultTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) { + return _OperatorFeeVault.contract.Transact(opts, "withdraw") +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns(uint256 value_) +func (_OperatorFeeVault *OperatorFeeVaultSession) Withdraw() (*types.Transaction, error) { + return _OperatorFeeVault.Contract.Withdraw(&_OperatorFeeVault.TransactOpts) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns(uint256 value_) +func (_OperatorFeeVault *OperatorFeeVaultTransactorSession) Withdraw() (*types.Transaction, error) { + return _OperatorFeeVault.Contract.Withdraw(&_OperatorFeeVault.TransactOpts) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _OperatorFeeVault.contract.RawTransact(opts, nil) // calldata is disallowed for receive function +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_OperatorFeeVault *OperatorFeeVaultSession) Receive() (*types.Transaction, error) { + return _OperatorFeeVault.Contract.Receive(&_OperatorFeeVault.TransactOpts) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_OperatorFeeVault *OperatorFeeVaultTransactorSession) Receive() (*types.Transaction, error) { + return _OperatorFeeVault.Contract.Receive(&_OperatorFeeVault.TransactOpts) +} + +// OperatorFeeVaultInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the OperatorFeeVault contract. +type OperatorFeeVaultInitializedIterator struct { + Event *OperatorFeeVaultInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OperatorFeeVaultInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OperatorFeeVaultInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OperatorFeeVaultInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OperatorFeeVaultInitialized represents a Initialized event raised by the OperatorFeeVault contract. +type OperatorFeeVaultInitialized struct { + Version uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) FilterInitialized(opts *bind.FilterOpts) (*OperatorFeeVaultInitializedIterator, error) { + + logs, sub, err := _OperatorFeeVault.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &OperatorFeeVaultInitializedIterator{contract: _OperatorFeeVault.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *OperatorFeeVaultInitialized) (event.Subscription, error) { + + logs, sub, err := _OperatorFeeVault.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OperatorFeeVaultInitialized) + if err := _OperatorFeeVault.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) ParseInitialized(log types.Log) (*OperatorFeeVaultInitialized, error) { + event := new(OperatorFeeVaultInitialized) + if err := _OperatorFeeVault.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// OperatorFeeVaultMinWithdrawalAmountUpdatedIterator is returned from FilterMinWithdrawalAmountUpdated and is used to iterate over the raw logs and unpacked data for MinWithdrawalAmountUpdated events raised by the OperatorFeeVault contract. +type OperatorFeeVaultMinWithdrawalAmountUpdatedIterator struct { + Event *OperatorFeeVaultMinWithdrawalAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OperatorFeeVaultMinWithdrawalAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultMinWithdrawalAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultMinWithdrawalAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OperatorFeeVaultMinWithdrawalAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OperatorFeeVaultMinWithdrawalAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OperatorFeeVaultMinWithdrawalAmountUpdated represents a MinWithdrawalAmountUpdated event raised by the OperatorFeeVault contract. +type OperatorFeeVaultMinWithdrawalAmountUpdated struct { + OldWithdrawalAmount *big.Int + NewWithdrawalAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMinWithdrawalAmountUpdated is a free log retrieval operation binding the contract event 0x895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e4203. +// +// Solidity: event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) FilterMinWithdrawalAmountUpdated(opts *bind.FilterOpts) (*OperatorFeeVaultMinWithdrawalAmountUpdatedIterator, error) { + + logs, sub, err := _OperatorFeeVault.contract.FilterLogs(opts, "MinWithdrawalAmountUpdated") + if err != nil { + return nil, err + } + return &OperatorFeeVaultMinWithdrawalAmountUpdatedIterator{contract: _OperatorFeeVault.contract, event: "MinWithdrawalAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchMinWithdrawalAmountUpdated is a free log subscription operation binding the contract event 0x895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e4203. +// +// Solidity: event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) WatchMinWithdrawalAmountUpdated(opts *bind.WatchOpts, sink chan<- *OperatorFeeVaultMinWithdrawalAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _OperatorFeeVault.contract.WatchLogs(opts, "MinWithdrawalAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OperatorFeeVaultMinWithdrawalAmountUpdated) + if err := _OperatorFeeVault.contract.UnpackLog(event, "MinWithdrawalAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMinWithdrawalAmountUpdated is a log parse operation binding the contract event 0x895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e4203. +// +// Solidity: event MinWithdrawalAmountUpdated(uint256 oldWithdrawalAmount, uint256 newWithdrawalAmount) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) ParseMinWithdrawalAmountUpdated(log types.Log) (*OperatorFeeVaultMinWithdrawalAmountUpdated, error) { + event := new(OperatorFeeVaultMinWithdrawalAmountUpdated) + if err := _OperatorFeeVault.contract.UnpackLog(event, "MinWithdrawalAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// OperatorFeeVaultRecipientUpdatedIterator is returned from FilterRecipientUpdated and is used to iterate over the raw logs and unpacked data for RecipientUpdated events raised by the OperatorFeeVault contract. +type OperatorFeeVaultRecipientUpdatedIterator struct { + Event *OperatorFeeVaultRecipientUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OperatorFeeVaultRecipientUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultRecipientUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultRecipientUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OperatorFeeVaultRecipientUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OperatorFeeVaultRecipientUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OperatorFeeVaultRecipientUpdated represents a RecipientUpdated event raised by the OperatorFeeVault contract. +type OperatorFeeVaultRecipientUpdated struct { + OldRecipient common.Address + NewRecipient common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRecipientUpdated is a free log retrieval operation binding the contract event 0x62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e4593. +// +// Solidity: event RecipientUpdated(address oldRecipient, address newRecipient) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) FilterRecipientUpdated(opts *bind.FilterOpts) (*OperatorFeeVaultRecipientUpdatedIterator, error) { + + logs, sub, err := _OperatorFeeVault.contract.FilterLogs(opts, "RecipientUpdated") + if err != nil { + return nil, err + } + return &OperatorFeeVaultRecipientUpdatedIterator{contract: _OperatorFeeVault.contract, event: "RecipientUpdated", logs: logs, sub: sub}, nil +} + +// WatchRecipientUpdated is a free log subscription operation binding the contract event 0x62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e4593. +// +// Solidity: event RecipientUpdated(address oldRecipient, address newRecipient) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) WatchRecipientUpdated(opts *bind.WatchOpts, sink chan<- *OperatorFeeVaultRecipientUpdated) (event.Subscription, error) { + + logs, sub, err := _OperatorFeeVault.contract.WatchLogs(opts, "RecipientUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OperatorFeeVaultRecipientUpdated) + if err := _OperatorFeeVault.contract.UnpackLog(event, "RecipientUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRecipientUpdated is a log parse operation binding the contract event 0x62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e4593. +// +// Solidity: event RecipientUpdated(address oldRecipient, address newRecipient) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) ParseRecipientUpdated(log types.Log) (*OperatorFeeVaultRecipientUpdated, error) { + event := new(OperatorFeeVaultRecipientUpdated) + if err := _OperatorFeeVault.contract.UnpackLog(event, "RecipientUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// OperatorFeeVaultWithdrawalIterator is returned from FilterWithdrawal and is used to iterate over the raw logs and unpacked data for Withdrawal events raised by the OperatorFeeVault contract. +type OperatorFeeVaultWithdrawalIterator struct { + Event *OperatorFeeVaultWithdrawal // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OperatorFeeVaultWithdrawalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultWithdrawal) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultWithdrawal) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OperatorFeeVaultWithdrawalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OperatorFeeVaultWithdrawalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OperatorFeeVaultWithdrawal represents a Withdrawal event raised by the OperatorFeeVault contract. +type OperatorFeeVaultWithdrawal struct { + Value *big.Int + To common.Address + From common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawal is a free log retrieval operation binding the contract event 0xc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba. +// +// Solidity: event Withdrawal(uint256 value, address to, address from) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) FilterWithdrawal(opts *bind.FilterOpts) (*OperatorFeeVaultWithdrawalIterator, error) { + + logs, sub, err := _OperatorFeeVault.contract.FilterLogs(opts, "Withdrawal") + if err != nil { + return nil, err + } + return &OperatorFeeVaultWithdrawalIterator{contract: _OperatorFeeVault.contract, event: "Withdrawal", logs: logs, sub: sub}, nil +} + +// WatchWithdrawal is a free log subscription operation binding the contract event 0xc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba. +// +// Solidity: event Withdrawal(uint256 value, address to, address from) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *OperatorFeeVaultWithdrawal) (event.Subscription, error) { + + logs, sub, err := _OperatorFeeVault.contract.WatchLogs(opts, "Withdrawal") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OperatorFeeVaultWithdrawal) + if err := _OperatorFeeVault.contract.UnpackLog(event, "Withdrawal", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawal is a log parse operation binding the contract event 0xc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba. +// +// Solidity: event Withdrawal(uint256 value, address to, address from) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) ParseWithdrawal(log types.Log) (*OperatorFeeVaultWithdrawal, error) { + event := new(OperatorFeeVaultWithdrawal) + if err := _OperatorFeeVault.contract.UnpackLog(event, "Withdrawal", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// OperatorFeeVaultWithdrawal0Iterator is returned from FilterWithdrawal0 and is used to iterate over the raw logs and unpacked data for Withdrawal0 events raised by the OperatorFeeVault contract. +type OperatorFeeVaultWithdrawal0Iterator struct { + Event *OperatorFeeVaultWithdrawal0 // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OperatorFeeVaultWithdrawal0Iterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultWithdrawal0) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultWithdrawal0) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OperatorFeeVaultWithdrawal0Iterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OperatorFeeVaultWithdrawal0Iterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OperatorFeeVaultWithdrawal0 represents a Withdrawal0 event raised by the OperatorFeeVault contract. +type OperatorFeeVaultWithdrawal0 struct { + Value *big.Int + To common.Address + From common.Address + WithdrawalNetwork uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawal0 is a free log retrieval operation binding the contract event 0x38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee. +// +// Solidity: event Withdrawal(uint256 value, address to, address from, uint8 withdrawalNetwork) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) FilterWithdrawal0(opts *bind.FilterOpts) (*OperatorFeeVaultWithdrawal0Iterator, error) { + + logs, sub, err := _OperatorFeeVault.contract.FilterLogs(opts, "Withdrawal0") + if err != nil { + return nil, err + } + return &OperatorFeeVaultWithdrawal0Iterator{contract: _OperatorFeeVault.contract, event: "Withdrawal0", logs: logs, sub: sub}, nil +} + +// WatchWithdrawal0 is a free log subscription operation binding the contract event 0x38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee. +// +// Solidity: event Withdrawal(uint256 value, address to, address from, uint8 withdrawalNetwork) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) WatchWithdrawal0(opts *bind.WatchOpts, sink chan<- *OperatorFeeVaultWithdrawal0) (event.Subscription, error) { + + logs, sub, err := _OperatorFeeVault.contract.WatchLogs(opts, "Withdrawal0") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OperatorFeeVaultWithdrawal0) + if err := _OperatorFeeVault.contract.UnpackLog(event, "Withdrawal0", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawal0 is a log parse operation binding the contract event 0x38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee. +// +// Solidity: event Withdrawal(uint256 value, address to, address from, uint8 withdrawalNetwork) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) ParseWithdrawal0(log types.Log) (*OperatorFeeVaultWithdrawal0, error) { + event := new(OperatorFeeVaultWithdrawal0) + if err := _OperatorFeeVault.contract.UnpackLog(event, "Withdrawal0", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// OperatorFeeVaultWithdrawalNetworkUpdatedIterator is returned from FilterWithdrawalNetworkUpdated and is used to iterate over the raw logs and unpacked data for WithdrawalNetworkUpdated events raised by the OperatorFeeVault contract. +type OperatorFeeVaultWithdrawalNetworkUpdatedIterator struct { + Event *OperatorFeeVaultWithdrawalNetworkUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OperatorFeeVaultWithdrawalNetworkUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultWithdrawalNetworkUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OperatorFeeVaultWithdrawalNetworkUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OperatorFeeVaultWithdrawalNetworkUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OperatorFeeVaultWithdrawalNetworkUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OperatorFeeVaultWithdrawalNetworkUpdated represents a WithdrawalNetworkUpdated event raised by the OperatorFeeVault contract. +type OperatorFeeVaultWithdrawalNetworkUpdated struct { + OldWithdrawalNetwork uint8 + NewWithdrawalNetwork uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalNetworkUpdated is a free log retrieval operation binding the contract event 0xf2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc8. +// +// Solidity: event WithdrawalNetworkUpdated(uint8 oldWithdrawalNetwork, uint8 newWithdrawalNetwork) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) FilterWithdrawalNetworkUpdated(opts *bind.FilterOpts) (*OperatorFeeVaultWithdrawalNetworkUpdatedIterator, error) { + + logs, sub, err := _OperatorFeeVault.contract.FilterLogs(opts, "WithdrawalNetworkUpdated") + if err != nil { + return nil, err + } + return &OperatorFeeVaultWithdrawalNetworkUpdatedIterator{contract: _OperatorFeeVault.contract, event: "WithdrawalNetworkUpdated", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalNetworkUpdated is a free log subscription operation binding the contract event 0xf2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc8. +// +// Solidity: event WithdrawalNetworkUpdated(uint8 oldWithdrawalNetwork, uint8 newWithdrawalNetwork) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) WatchWithdrawalNetworkUpdated(opts *bind.WatchOpts, sink chan<- *OperatorFeeVaultWithdrawalNetworkUpdated) (event.Subscription, error) { + + logs, sub, err := _OperatorFeeVault.contract.WatchLogs(opts, "WithdrawalNetworkUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OperatorFeeVaultWithdrawalNetworkUpdated) + if err := _OperatorFeeVault.contract.UnpackLog(event, "WithdrawalNetworkUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalNetworkUpdated is a log parse operation binding the contract event 0xf2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc8. +// +// Solidity: event WithdrawalNetworkUpdated(uint8 oldWithdrawalNetwork, uint8 newWithdrawalNetwork) +func (_OperatorFeeVault *OperatorFeeVaultFilterer) ParseWithdrawalNetworkUpdated(log types.Log) (*OperatorFeeVaultWithdrawalNetworkUpdated, error) { + event := new(OperatorFeeVaultWithdrawalNetworkUpdated) + if err := _OperatorFeeVault.contract.UnpackLog(event, "WithdrawalNetworkUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/op-service/predeploys/addresses.go b/op-service/predeploys/addresses.go index e461f0c86fa..78bcc68c8cd 100644 --- a/op-service/predeploys/addresses.go +++ b/op-service/predeploys/addresses.go @@ -31,6 +31,7 @@ const ( SuperchainETHBridge = "0x4200000000000000000000000000000000000024" ETHLiquidity = "0x4200000000000000000000000000000000000025" SuperchainTokenBridge = "0x4200000000000000000000000000000000000028" + FeeSplitter = "0x420000000000000000000000000000000000002b" Create2Deployer = "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2" MultiCall3 = "0xcA11bde05977b3631167028862bE2a173976CA11" Safe_v130 = "0x69f4D1788e39c87893C980c06EdF4b7f686e2938" @@ -72,6 +73,7 @@ var ( SuperchainETHBridgeAddr = common.HexToAddress(SuperchainETHBridge) ETHLiquidityAddr = common.HexToAddress(ETHLiquidity) SuperchainTokenBridgeAddr = common.HexToAddress(SuperchainTokenBridge) + FeeSplitterAddr = common.HexToAddress(FeeSplitter) Create2DeployerAddr = common.HexToAddress(Create2Deployer) MultiCall3Addr = common.HexToAddress(MultiCall3) Safe_v130Addr = common.HexToAddress(Safe_v130) @@ -106,6 +108,7 @@ func init() { Predeploys["SuperchainETHBridge"] = &Predeploy{Address: SuperchainETHBridgeAddr} Predeploys["ETHLiquidity"] = &Predeploy{Address: ETHLiquidityAddr} Predeploys["SuperchainTokenBridge"] = &Predeploy{Address: SuperchainTokenBridgeAddr} + Predeploys["FeeSplitter"] = &Predeploy{Address: FeeSplitterAddr} Predeploys["GovernanceToken"] = &Predeploy{ Address: GovernanceTokenAddr, ProxyDisabled: true, From fc8afbc9265400ecab4249a7cc5836f5f35c15ad Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:59:08 -0300 Subject: [PATCH 06/11] fix: getter incompleteness (#646) --- .../contracts-bedrock/scripts/Artifacts.s.sol | 2 + .../contracts-bedrock/scripts/L2Genesis.s.sol | 134 ++++++++---------- .../scripts/libraries/ForgeArtifacts.sol | 10 ++ .../test/libraries/Predeploys.t.sol | 29 +++- .../test/scripts/L2Genesis.t.sol | 38 ++++- 5 files changed, 131 insertions(+), 82 deletions(-) diff --git a/packages/contracts-bedrock/scripts/Artifacts.s.sol b/packages/contracts-bedrock/scripts/Artifacts.s.sol index 5858c8aa4c5..fac400dd68b 100644 --- a/packages/contracts-bedrock/scripts/Artifacts.s.sol +++ b/packages/contracts-bedrock/scripts/Artifacts.s.sol @@ -130,6 +130,8 @@ contract Artifacts { return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON); } else if (digest == keccak256(bytes("SuperchainTokenBridge"))) { return payable(Predeploys.SUPERCHAIN_TOKEN_BRIDGE); + } else if (digest == keccak256(bytes("FeeSplitter"))) { + return payable(Predeploys.FEE_SPLITTER); } return payable(address(0)); } diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index aaff71e026a..cd6a7d7dc5b 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -312,25 +312,12 @@ contract L2Genesis is Script { /// @notice This predeploy is following the safety invariant #2, function setSequencerFeeVault(Input memory _input) internal { - address recipient; - Types.WithdrawalNetwork network; - if (_input.useRevenueShare) { - recipient = Predeploys.FEE_SPLITTER; - network = Types.WithdrawalNetwork.L2; - } else { - recipient = _input.sequencerFeeVaultRecipient; - network = Types.WithdrawalNetwork(_input.sequencerFeeVaultWithdrawalNetwork); - } - - address impl = _setImplementationCode(Predeploys.SEQUENCER_FEE_WALLET); - - /// Initialize the implemenation using max value for min withdrawal amount to make it unusable - ISequencerFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); - // Initialize the predeploy - ISequencerFeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)).initialize({ - _recipient: recipient, + _setFeeVault({ + _vaultAddr: Predeploys.SEQUENCER_FEE_WALLET, + _useRevenueShare: _input.useRevenueShare, + _recipient: _input.sequencerFeeVaultRecipient, _minWithdrawalAmount: _input.sequencerFeeVaultMinimumWithdrawalAmount, - _withdrawalNetwork: network + _withdrawalNetwork: Types.WithdrawalNetwork(_input.sequencerFeeVaultWithdrawalNetwork) }); } @@ -402,73 +389,34 @@ contract L2Genesis is Script { /// @notice This predeploy is following the safety invariant #2. function setBaseFeeVault(Input memory _input) internal { - address recipient; - Types.WithdrawalNetwork network; - if (_input.useRevenueShare) { - recipient = Predeploys.FEE_SPLITTER; - network = Types.WithdrawalNetwork.L2; - } else { - recipient = _input.baseFeeVaultRecipient; - network = Types.WithdrawalNetwork(_input.baseFeeVaultWithdrawalNetwork); - } - - address impl = _setImplementationCode(Predeploys.BASE_FEE_VAULT); - - /// Initialize the implementation using max value for min withdrawal amount to make it unusable - IBaseFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); - // Initialize the predeploy - IBaseFeeVault(payable(Predeploys.BASE_FEE_VAULT)).initialize({ - _recipient: recipient, + _setFeeVault({ + _vaultAddr: Predeploys.BASE_FEE_VAULT, + _useRevenueShare: _input.useRevenueShare, + _recipient: _input.baseFeeVaultRecipient, _minWithdrawalAmount: _input.baseFeeVaultMinimumWithdrawalAmount, - _withdrawalNetwork: network + _withdrawalNetwork: Types.WithdrawalNetwork(_input.baseFeeVaultWithdrawalNetwork) }); } /// @notice This predeploy is following the safety invariant #2. function setL1FeeVault(Input memory _input) internal { - address recipient; - Types.WithdrawalNetwork network; - if (_input.useRevenueShare) { - recipient = Predeploys.FEE_SPLITTER; - network = Types.WithdrawalNetwork.L2; - } else { - recipient = _input.l1FeeVaultRecipient; - network = Types.WithdrawalNetwork(_input.l1FeeVaultWithdrawalNetwork); - } - - address impl = _setImplementationCode(Predeploys.L1_FEE_VAULT); - - /// Initialize the implementation using max value for min withdrawal amount to make it unusable - IL1FeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); - // Initialize the predeploy - IL1FeeVault(payable(Predeploys.L1_FEE_VAULT)).initialize({ - _recipient: recipient, + _setFeeVault({ + _vaultAddr: Predeploys.L1_FEE_VAULT, + _useRevenueShare: _input.useRevenueShare, + _recipient: _input.l1FeeVaultRecipient, _minWithdrawalAmount: _input.l1FeeVaultMinimumWithdrawalAmount, - _withdrawalNetwork: network + _withdrawalNetwork: Types.WithdrawalNetwork(_input.l1FeeVaultWithdrawalNetwork) }); } /// @notice This predeploy is following the safety invariant #2. function setOperatorFeeVault(Input memory _input) internal { - address recipient; - Types.WithdrawalNetwork network; - if (_input.useRevenueShare) { - recipient = Predeploys.FEE_SPLITTER; - network = Types.WithdrawalNetwork.L2; - } else { - recipient = _input.operatorFeeVaultRecipient; - network = Types.WithdrawalNetwork(_input.operatorFeeVaultWithdrawalNetwork); - } - - address impl = _setImplementationCode(Predeploys.OPERATOR_FEE_VAULT); - - /// Initialize the implementation using max value for min withdrawal amount to make it unusable - IOperatorFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); - // Initialize the predeploy - IOperatorFeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)).initialize({ - _recipient: recipient, + _setFeeVault({ + _vaultAddr: Predeploys.OPERATOR_FEE_VAULT, + _useRevenueShare: _input.useRevenueShare, + _recipient: _input.operatorFeeVaultRecipient, _minWithdrawalAmount: _input.operatorFeeVaultMinimumWithdrawalAmount, - _withdrawalNetwork: network + _withdrawalNetwork: Types.WithdrawalNetwork(_input.operatorFeeVaultWithdrawalNetwork) }); } @@ -678,6 +626,48 @@ contract L2Genesis is Script { return impl; } + /// @notice Helper function to set up a fee vault predeploy with revenue sharing support. + /// This follows safety invariant #2 (initializable contracts). + /// @param _vaultAddr The predeploy address of the fee vault. + /// @param _useRevenueShare Whether revenue sharing is enabled. + /// @param _recipient The recipient address (ignored if revenue sharing is enabled). + /// @param _minWithdrawalAmount The minimum withdrawal amount (ignored if revenue sharing is enabled). + /// @param _withdrawalNetwork The withdrawal network (ignored if revenue sharing is enabled). + function _setFeeVault( + address _vaultAddr, + bool _useRevenueShare, + address _recipient, + uint256 _minWithdrawalAmount, + Types.WithdrawalNetwork _withdrawalNetwork + ) + internal + { + address recipient; + Types.WithdrawalNetwork network; + uint256 minWithdrawalAmount; + + if (_useRevenueShare) { + recipient = Predeploys.FEE_SPLITTER; + network = Types.WithdrawalNetwork.L2; + minWithdrawalAmount = 0; + } else { + recipient = _recipient; + network = _withdrawalNetwork; + minWithdrawalAmount = _minWithdrawalAmount; + } + + address impl = _setImplementationCode(_vaultAddr); + + /// Initialize the implementation using max value for min withdrawal amount to make it unusable + IFeeVault(payable(impl)).initialize(address(0), type(uint256).max, Types.WithdrawalNetwork.L1); + // Initialize the predeploy + IFeeVault(payable(_vaultAddr)).initialize({ + _recipient: recipient, + _minWithdrawalAmount: minWithdrawalAmount, + _withdrawalNetwork: network + }); + } + /// @notice Funds the default dev accounts with ether function fundDevAccounts() internal { for (uint256 i; i < devAccounts.length; i++) { diff --git a/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol b/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol index de00f7e4ec6..847145434b5 100644 --- a/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol +++ b/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol @@ -218,6 +218,16 @@ library ForgeArtifacts { initialized_ = uint8((uint256(slotVal) >> (slot.offset * 8)) & 0xFF) != 0; } + /// @notice Checks if a contract is initialized using OpenZeppelin v5 namespaced storage pattern. + /// OZ v5 storage slot: keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) + /// & ~bytes32(uint256(0xff)) + function isInitializedV5(address _addr) internal view returns (bool) { + bytes32 INITIALIZABLE_STORAGE_SLOT = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + bytes32 slotVal = vm.load(_addr, INITIALIZABLE_STORAGE_SLOT); + // In OZ v5, byte 0 is _initialized, byte 1 is _initializing + return uint8(uint256(slotVal) & 0xFF) != 0; + } + /// @notice Returns the names of all contracts in a given directory. /// @param _path The path to search for contracts. /// @param _pathExcludes An array of paths to exclude from the search. diff --git a/packages/contracts-bedrock/test/libraries/Predeploys.t.sol b/packages/contracts-bedrock/test/libraries/Predeploys.t.sol index 0073dc93379..936ec8f000c 100644 --- a/packages/contracts-bedrock/test/libraries/Predeploys.t.sol +++ b/packages/contracts-bedrock/test/libraries/Predeploys.t.sol @@ -28,18 +28,25 @@ abstract contract Predeploys_TestInit is CommonTest { return _addr == Predeploys.L1_MESSAGE_SENDER; } - /// @notice Returns true if the predeploy is initializable. - function _isInitializable(address _addr) internal pure returns (bool) { + /// @notice Returns true if the predeploy is initializable and uses OpenZeppelin v4 storage pattern. + /// These contracts have _initialized in the regular storage layout. + function _isInitializableV4(address _addr) internal pure returns (bool) { return _addr == Predeploys.L2_CROSS_DOMAIN_MESSENGER || _addr == Predeploys.L2_STANDARD_BRIDGE || _addr == Predeploys.L2_ERC721_BRIDGE || _addr == Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY || _addr == Predeploys.FEE_SPLITTER; } + /// @notice Returns true if the predeploy is initializable and uses OpenZeppelin v5 namespaced storage (EIP-7201). + /// These contracts store _initialized in a namespaced slot, not in the regular storage layout. + function _isInitializableV5(address _addr) internal pure returns (bool) { + return _addr == Predeploys.SEQUENCER_FEE_WALLET || _addr == Predeploys.BASE_FEE_VAULT + || _addr == Predeploys.L1_FEE_VAULT || _addr == Predeploys.OPERATOR_FEE_VAULT; + } + /// @notice Returns true if the predeploy uses immutables. function _usesImmutables(address _addr) internal pure returns (bool) { - return _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.SEQUENCER_FEE_WALLET - || _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT - || _addr == Predeploys.OPERATOR_FEE_VAULT || _addr == Predeploys.EAS || _addr == Predeploys.GOVERNANCE_TOKEN; + return _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.EAS + || _addr == Predeploys.GOVERNANCE_TOKEN; } /// @notice Internal test function for predeploys validation across different forks. @@ -99,10 +106,20 @@ abstract contract Predeploys_TestInit is CommonTest { assertEq(implAddr.code, supposedCode, "proxy implementation contract should match contract source"); } - if (_isInitializable(addr)) { + if (_isInitializableV4(addr)) { assertTrue(ForgeArtifacts.isInitialized({ _name: cname, _address: addr })); assertTrue(ForgeArtifacts.isInitialized({ _name: cname, _address: implAddr })); } + + if (_isInitializableV5(addr)) { + assertTrue( + ForgeArtifacts.isInitializedV5(addr), string.concat("V5 proxy not initialized: ", vm.toString(addr)) + ); + assertTrue( + ForgeArtifacts.isInitializedV5(implAddr), + string.concat("V5 implementation not initialized: ", vm.toString(implAddr)) + ); + } } } } diff --git a/packages/contracts-bedrock/test/scripts/L2Genesis.t.sol b/packages/contracts-bedrock/test/scripts/L2Genesis.t.sol index 05cac30d1ce..5c043befb66 100644 --- a/packages/contracts-bedrock/test/scripts/L2Genesis.t.sol +++ b/packages/contracts-bedrock/test/scripts/L2Genesis.t.sol @@ -10,6 +10,7 @@ import { ISuperchainRevSharesCalculator } from "interfaces/L2/ISuperchainRevShar import { ISequencerFeeVault } from "interfaces/L2/ISequencerFeeVault.sol"; import { IBaseFeeVault } from "interfaces/L2/IBaseFeeVault.sol"; import { IL1FeeVault } from "interfaces/L2/IL1FeeVault.sol"; +import { IOperatorFeeVault } from "interfaces/L2/IOperatorFeeVault.sol"; import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; import { IOptimismMintableERC721Factory } from "interfaces/L2/IOptimismMintableERC721Factory.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; @@ -69,18 +70,35 @@ abstract contract L2Genesis_TestInit is Test { IBaseFeeVault baseFeeVault = IBaseFeeVault(payable(Predeploys.BASE_FEE_VAULT)); IL1FeeVault l1FeeVault = IL1FeeVault(payable(Predeploys.L1_FEE_VAULT)); ISequencerFeeVault sequencerFeeVault = ISequencerFeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)); + IOperatorFeeVault operatorFeeVault = IOperatorFeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)); + assertEq(baseFeeVault.RECIPIENT(), input.baseFeeVaultRecipient); assertEq(baseFeeVault.recipient(), input.baseFeeVaultRecipient); assertEq(baseFeeVault.MIN_WITHDRAWAL_AMOUNT(), input.baseFeeVaultMinimumWithdrawalAmount); + assertEq(baseFeeVault.minWithdrawalAmount(), input.baseFeeVaultMinimumWithdrawalAmount); assertEq(uint8(baseFeeVault.WITHDRAWAL_NETWORK()), uint8(input.baseFeeVaultWithdrawalNetwork)); + assertEq(uint8(baseFeeVault.withdrawalNetwork()), uint8(input.baseFeeVaultWithdrawalNetwork)); + assertEq(l1FeeVault.RECIPIENT(), input.l1FeeVaultRecipient); assertEq(l1FeeVault.recipient(), input.l1FeeVaultRecipient); assertEq(l1FeeVault.MIN_WITHDRAWAL_AMOUNT(), input.l1FeeVaultMinimumWithdrawalAmount); + assertEq(l1FeeVault.minWithdrawalAmount(), input.l1FeeVaultMinimumWithdrawalAmount); assertEq(uint8(l1FeeVault.WITHDRAWAL_NETWORK()), uint8(input.l1FeeVaultWithdrawalNetwork)); + assertEq(uint8(l1FeeVault.withdrawalNetwork()), uint8(input.l1FeeVaultWithdrawalNetwork)); + assertEq(sequencerFeeVault.RECIPIENT(), input.sequencerFeeVaultRecipient); assertEq(sequencerFeeVault.recipient(), input.sequencerFeeVaultRecipient); assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), input.sequencerFeeVaultMinimumWithdrawalAmount); + assertEq(sequencerFeeVault.minWithdrawalAmount(), input.sequencerFeeVaultMinimumWithdrawalAmount); assertEq(uint8(sequencerFeeVault.WITHDRAWAL_NETWORK()), uint8(input.sequencerFeeVaultWithdrawalNetwork)); + assertEq(uint8(sequencerFeeVault.withdrawalNetwork()), uint8(input.sequencerFeeVaultWithdrawalNetwork)); + + assertEq(operatorFeeVault.RECIPIENT(), input.operatorFeeVaultRecipient); + assertEq(operatorFeeVault.recipient(), input.operatorFeeVaultRecipient); + assertEq(operatorFeeVault.MIN_WITHDRAWAL_AMOUNT(), input.operatorFeeVaultMinimumWithdrawalAmount); + assertEq(operatorFeeVault.minWithdrawalAmount(), input.operatorFeeVaultMinimumWithdrawalAmount); + assertEq(uint8(operatorFeeVault.WITHDRAWAL_NETWORK()), uint8(input.operatorFeeVaultWithdrawalNetwork)); + assertEq(uint8(operatorFeeVault.withdrawalNetwork()), uint8(input.operatorFeeVaultWithdrawalNetwork)); } function testVaultsWithRevenueShare() internal view { @@ -90,20 +108,32 @@ abstract contract L2Genesis_TestInit is Test { IFeeVault operatorFeeVault = IFeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)); assertEq(baseFeeVault.recipient(), Predeploys.FEE_SPLITTER); - assertEq(baseFeeVault.MIN_WITHDRAWAL_AMOUNT(), input.baseFeeVaultMinimumWithdrawalAmount); + assertEq(baseFeeVault.RECIPIENT(), Predeploys.FEE_SPLITTER); + assertEq(baseFeeVault.MIN_WITHDRAWAL_AMOUNT(), 0); + assertEq(baseFeeVault.minWithdrawalAmount(), 0); assertEq(uint8(baseFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(uint8(baseFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(l1FeeVault.RECIPIENT(), Predeploys.FEE_SPLITTER); assertEq(l1FeeVault.recipient(), Predeploys.FEE_SPLITTER); - assertEq(l1FeeVault.MIN_WITHDRAWAL_AMOUNT(), input.l1FeeVaultMinimumWithdrawalAmount); + assertEq(l1FeeVault.MIN_WITHDRAWAL_AMOUNT(), 0); + assertEq(l1FeeVault.minWithdrawalAmount(), 0); assertEq(uint8(l1FeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(uint8(l1FeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(sequencerFeeVault.RECIPIENT(), Predeploys.FEE_SPLITTER); assertEq(sequencerFeeVault.recipient(), Predeploys.FEE_SPLITTER); - assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), input.sequencerFeeVaultMinimumWithdrawalAmount); + assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), 0); + assertEq(sequencerFeeVault.minWithdrawalAmount(), 0); assertEq(uint8(sequencerFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(uint8(sequencerFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(operatorFeeVault.RECIPIENT(), Predeploys.FEE_SPLITTER); assertEq(operatorFeeVault.recipient(), Predeploys.FEE_SPLITTER); - assertEq(operatorFeeVault.MIN_WITHDRAWAL_AMOUNT(), input.operatorFeeVaultMinimumWithdrawalAmount); + assertEq(operatorFeeVault.MIN_WITHDRAWAL_AMOUNT(), 0); + assertEq(operatorFeeVault.minWithdrawalAmount(), 0); assertEq(uint8(operatorFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(uint8(operatorFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); } function testGovernance() internal view { From 7172dc15fb72d52abe59c3d21ac0860d7c3282ab Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:44:54 -0300 Subject: [PATCH 07/11] fix: timestamp on initialize (#645) --- packages/contracts-bedrock/src/L2/FeeSplitter.sol | 3 +++ packages/contracts-bedrock/test/L2/FeeSplitter.t.sol | 1 + 2 files changed, 4 insertions(+) diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index fdffea79b03..53361f3daac 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -112,6 +112,9 @@ contract FeeSplitter is ISemver, Initializable { sharesCalculator = _sharesCalculator; // As default, the fee disbursement interval is 1 day feeDisbursementInterval = 1 days; + + // Set the last disbursement time to the current block timestamp + lastDisbursementTime = uint128(block.timestamp); } /// @dev Receives ETH fees withdrawn from L2 FeeVaults. diff --git a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol index 54f2a6330ae..387ef9f187f 100644 --- a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol @@ -111,6 +111,7 @@ contract FeeSplitter_Initialize_Test is FeeSplitter_TestInit { assertEq(address(IFeeSplitter(payable(impl)).sharesCalculator()), address(_defaultSharesCalculator)); assertEq(IFeeSplitter(payable(impl)).feeDisbursementInterval(), 1 days); + assertEq(IFeeSplitter(payable(impl)).lastDisbursementTime(), block.timestamp); } /// @notice Test that the implementation contract disables initializers in the constructor From 73799ba2d75179356317c70bca49d0ae91a5997d Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:51:34 -0300 Subject: [PATCH 08/11] fix: comments and tags (#650) --- op-deployer/book/src/user-guide/init.md | 2 ++ .../contracts-bedrock/book/src/contributing/style-guide.md | 7 +------ packages/contracts-bedrock/src/L2/FeeSplitter.sol | 5 +++-- packages/contracts-bedrock/src/L2/FeeVault.sol | 7 ++++--- .../src/L2/SuperchainRevSharesCalculator.sol | 3 ++- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/op-deployer/book/src/user-guide/init.md b/op-deployer/book/src/user-guide/init.md index a82f917652e..56f357e4e72 100644 --- a/op-deployer/book/src/user-guide/init.md +++ b/op-deployer/book/src/user-guide/init.md @@ -44,6 +44,7 @@ l2ContractsLocator = "tag://op-contracts/v1.7.0-beta.1+l2-contracts" baseFeeVaultRecipient = "0x0000000000000000000000000000000000000000" l1FeeVaultRecipient = "0x0000000000000000000000000000000000000000" sequencerFeeVaultRecipient = "0x0000000000000000000000000000000000000000" + operatorFeeVaultRecipient = "0x0000000000000000000000000000000000000000" eip1559DenominatorCanyon = 250 eip1559Denominator = 50 eip1559Elasticity = 6 @@ -65,6 +66,7 @@ In production environments, you should use a more secure setup with cold-wallet * `baseFeeVaultRecipient` * `l1FeeVaultRecipient` * `sequencerFeeVaultRecipient` +* `operatorFeeVaultRecipient` * `l1ProxyAdminOwner` * `l2ProxyAdminOwner` * `systemConfigOwner` diff --git a/packages/contracts-bedrock/book/src/contributing/style-guide.md b/packages/contracts-bedrock/book/src/contributing/style-guide.md index a8686aa023f..4a5981b2499 100644 --- a/packages/contracts-bedrock/book/src/contributing/style-guide.md +++ b/packages/contracts-bedrock/book/src/contributing/style-guide.md @@ -389,9 +389,4 @@ Certain types of tests are excluded from standard naming conventions: - **Script tests** (`test/scripts/`): Test deployment and utility scripts - **Library tests** (`test/libraries/`): May have different artifact structures - **Formal verification** (`test/kontrol/`): Use specialized tooling conventions -- **Vendor tests** (`test/vendor/`): Test external code with different patterns - -## Withdrawing From Fee Vaults - -See the file `scripts/FeeVaultWithdrawal.s.sol` to withdraw from the L2 fee vaults. It includes -instructions on how to run it. `foundry` is required. +- **Vendor tests** (`test/vendor/`): Test external code with different patterns \ 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 53361f3daac..b3ff1cdf1cc 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -18,8 +18,8 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I /// @custom:proxied /// @custom:predeploy 0x420000000000000000000000000000000000002B /// @title FeeSplitter -/// @notice Withdraws funds from system FeeVault contracts, sends Optimism their revenue share, and -/// sends the remaining funds to the fee router. +/// @notice Withdraws funds from system FeeVault contracts and distributes them according to the +/// configured SharesCalculator. contract FeeSplitter is ISemver, Initializable { /// @notice Thrown when the fee disbursement interval exceeds the maximum allowed. error FeeSplitter_ExceedsMaxFeeDisbursementTime(); @@ -65,6 +65,7 @@ contract FeeSplitter is ISemver, Initializable { bytes32 internal constant _FEE_SPLITTER_IS_DISBURSING_SLOT = 0xe3007e9730850b5618eacb0537bef0cf0f1600267ae8549e472449d77b731e45; + /// @notice Semantic version. /// @custom:semver 1.0.0 string public constant version = "1.0.0"; diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 0e2259123ff..9f040f07150 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -39,6 +39,7 @@ abstract contract FeeVault is Initializable { /// @notice Reserve extra slots in the storage layout for future upgrades, 50 in total. uint256[46] private __gap; + /// @custom:legacy /// @notice Emitted each time a withdrawal occurs. This event will be deprecated /// in favor of the Withdrawal event containing the WithdrawalNetwork parameter. /// @param value Amount that was withdrawn (in wei). @@ -167,27 +168,27 @@ abstract contract FeeVault is Initializable { } } + /// @custom:legacy /// @notice Minimum balance before a withdrawal can be triggered. /// Use the `minWithdrawalAmount()` getter as this is deprecated /// and is subject to be removed in the future. - /// @custom:legacy function MIN_WITHDRAWAL_AMOUNT() public view returns (uint256) { return minWithdrawalAmount; } + /// @custom:legacy /// @notice Account that will receive the fees. Can be located on L1 or L2. /// Use the `recipient()` getter as this is deprecated /// and is subject to be removed in the future. - /// @custom:legacy /// @return The recipient address. function RECIPIENT() public view returns (address) { return recipient; } + /// @custom:legacy /// @notice Network which the recipient will receive fees on. /// Use the `withdrawalNetwork()` getter as this is deprecated /// and is subject to be removed in the future. - /// @custom:legacy function WITHDRAWAL_NETWORK() public view returns (Types.WithdrawalNetwork) { return withdrawalNetwork; } diff --git a/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol b/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol index ff3ec4f33f0..7270140a34f 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainRevSharesCalculator.sol @@ -12,7 +12,7 @@ import { ISharesCalculator } from "interfaces/L2/ISharesCalculator.sol"; /// @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. -/// The second configured recipient receives the full remainder via FeeSplitter's remainder send. +/// The second configured recipient receives the remaining revenue. contract SuperchainRevSharesCalculator is ISemver, ISharesCalculator { /// @notice Emitted when the share recipient is updated. /// @param oldShareRecipient The old share recipient address. @@ -30,6 +30,7 @@ contract SuperchainRevSharesCalculator is ISemver, ISharesCalculator { /// @notice Thrown when the gross share is zero. error SharesCalculator_ZeroGrossShare(); + /// @notice Semantic version. /// @custom:semver 1.0.0 string public constant version = "1.0.0"; From 3a8d109238fbfabb0d0c8acfea368a6e5c932d80 Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:27:38 -0300 Subject: [PATCH 09/11] chore: gas optimizations (#649) --- .../contracts-bedrock/src/L2/FeeSplitter.sol | 37 ++++++++++--------- .../contracts-bedrock/src/L2/FeeVault.sol | 10 +++-- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index b3ff1cdf1cc..a616d81a265 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -142,48 +142,49 @@ contract FeeSplitter is ISemver, Initializable { // Pull fees into the contract _setTransientDisbursing(true); - uint256 _sequencerFees = _feeVaultWithdrawal(payable(Predeploys.SEQUENCER_FEE_WALLET)); - uint256 _baseFees = _feeVaultWithdrawal(payable(Predeploys.BASE_FEE_VAULT)); - uint256 _l1Fees = _feeVaultWithdrawal(payable(Predeploys.L1_FEE_VAULT)); - uint256 _operatorFees = _feeVaultWithdrawal(payable(Predeploys.OPERATOR_FEE_VAULT)); + uint256 sequencerFees = _feeVaultWithdrawal(payable(Predeploys.SEQUENCER_FEE_WALLET)); + uint256 baseFees = _feeVaultWithdrawal(payable(Predeploys.BASE_FEE_VAULT)); + uint256 l1Fees = _feeVaultWithdrawal(payable(Predeploys.L1_FEE_VAULT)); + uint256 operatorFees = _feeVaultWithdrawal(payable(Predeploys.OPERATOR_FEE_VAULT)); _setTransientDisbursing(false); - uint256 _grossRevenue = _sequencerFees + _baseFees + _operatorFees + _l1Fees; + uint256 grossRevenue = sequencerFees + baseFees + operatorFees + l1Fees; // Revert if no fees were collected - if (_grossRevenue == 0) { + if (grossRevenue == 0) { revert FeeSplitter_NoFeesCollected(); } // Call to the sharesCalculator to determine the fee share recipients, amounts, withdrawal networks, and data // DoS risk if array size is too large. - (ISharesCalculator.ShareInfo[] memory _shareInfo) = - sharesCalculator.getRecipientsAndAmounts(_sequencerFees, _baseFees, _operatorFees, _l1Fees); + (ISharesCalculator.ShareInfo[] memory shareInfo) = + sharesCalculator.getRecipientsAndAmounts(sequencerFees, baseFees, operatorFees, l1Fees); + + uint256 shareInfoLength = shareInfo.length; // Ensure the share calculator returned valid data - if (_shareInfo.length == 0) revert FeeSplitter_FeeShareInfoEmpty(); + if (shareInfoLength == 0) revert FeeSplitter_FeeShareInfoEmpty(); // Loop through the recipients and their corresponding fee shares - uint256 _totalFeesDisbursed; - for (uint256 i; i < _shareInfo.length; i++) { - address payable _recipient = _shareInfo[i].recipient; - uint256 _feeShareAmount = _shareInfo[i].amount; + uint256 totalFeesDisbursed; + for (uint256 i; i < shareInfoLength; i++) { + uint256 feesAmount = shareInfo[i].amount; // Ensure the fee share is greater than zero - if (_feeShareAmount == 0) continue; + if (feesAmount == 0) continue; - bool success = SafeCall.send(address(_recipient), _feeShareAmount); + bool success = SafeCall.send(shareInfo[i].recipient, feesAmount); if (!success) { revert FeeSplitter_FailedToSendToRevenueShareRecipient(); } - _totalFeesDisbursed += _feeShareAmount; + totalFeesDisbursed += feesAmount; } // Ensure the total fees disbursed is equal to the gross revenue /// NOTE: Contract can hold some balance after disbursement if tokens are force sent (using SELFDESTRUCT). - if (_totalFeesDisbursed != _grossRevenue) revert FeeSplitter_SharesCalculatorMalformedOutput(); + if (totalFeesDisbursed != grossRevenue) revert FeeSplitter_SharesCalculatorMalformedOutput(); - emit FeesDisbursed({ shareInfo: _shareInfo, grossRevenue: _grossRevenue }); + emit FeesDisbursed({ shareInfo: shareInfo, grossRevenue: grossRevenue }); } /// @notice Updates the fee disbursement interval. Only callable by the ProxyAdmin owner. diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 9f040f07150..7443d2b57f9 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -153,15 +153,17 @@ abstract contract FeeVault is Initializable { value_ = address(this).balance; totalProcessed += value_; - emit Withdrawal(value_, recipient, msg.sender); - emit Withdrawal(value_, recipient, msg.sender, withdrawalNetwork); + address recipientAddr = recipient; + + emit Withdrawal(value_, recipientAddr, msg.sender); + emit Withdrawal(value_, recipientAddr, msg.sender, withdrawalNetwork); if (withdrawalNetwork == Types.WithdrawalNetwork.L2) { - bool success = SafeCall.send(recipient, value_); + bool success = SafeCall.send(recipientAddr, 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: recipientAddr, _gasLimit: _WITHDRAWAL_MIN_GAS, _data: hex"" }); From 768e2989b8cf57495af2acb9d4d68ecc97f40756 Mon Sep 17 00:00:00 2001 From: Disco <131301107+0xDiscotech@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:38:24 -0300 Subject: [PATCH 10/11] chore: add missing constants (#655) --- devnet-sdk/contracts/constants/constants.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devnet-sdk/contracts/constants/constants.go b/devnet-sdk/contracts/constants/constants.go index ba494a1721d..f0d76bcde53 100644 --- a/devnet-sdk/contracts/constants/constants.go +++ b/devnet-sdk/contracts/constants/constants.go @@ -22,6 +22,7 @@ var ( ProxyAdmin types.Address = common.HexToAddress("0x4200000000000000000000000000000000000018") BaseFeeVault types.Address = common.HexToAddress("0x4200000000000000000000000000000000000019") L1FeeVault types.Address = common.HexToAddress("0x420000000000000000000000000000000000001a") + OperatorFeeVault types.Address = common.HexToAddress("0x420000000000000000000000000000000000001B") SchemaRegistry types.Address = common.HexToAddress("0x4200000000000000000000000000000000000020") EAS types.Address = common.HexToAddress("0x4200000000000000000000000000000000000021") CrossL2Inbox types.Address = common.HexToAddress("0x4200000000000000000000000000000000000022") @@ -29,6 +30,7 @@ var ( SuperchainETHBridge types.Address = common.HexToAddress("0x4200000000000000000000000000000000000024") ETHLiquidity types.Address = common.HexToAddress("0x4200000000000000000000000000000000000025") SuperchainTokenBridge types.Address = common.HexToAddress("0x4200000000000000000000000000000000000028") + FeeSplitter types.Address = common.HexToAddress("0x420000000000000000000000000000000000002B") GovernanceToken types.Address = common.HexToAddress("0x4200000000000000000000000000000000000042") Create2Deployer types.Address = common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2") MultiCall3 types.Address = common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11") From 32dc14bc7274d0b1cde8b190ef9b4113e715cdfc Mon Sep 17 00:00:00 2001 From: Chiin <77933451+0xChin@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:19:40 -0300 Subject: [PATCH 11/11] fix: stricter receive checks (#647) --- .../interfaces/L2/IFeeSplitter.sol | 4 +- .../contracts-bedrock/scripts/L2Genesis.s.sol | 4 - .../contracts-bedrock/src/L2/FeeSplitter.sol | 58 +++---- .../test/L2/FeeSplitter.t.sol | 147 ++++++++++++++++-- .../test/L2/FeeSplitterVaults.t.sol | 70 +++++++++ .../contracts-bedrock/test/L2/FeeVault.t.sol | 2 +- .../test/mocks/MaliciousMockFeeVault.sol | 36 +++++ .../test/mocks/ReentrantMockFeeVault.sol | 40 +++++ 8 files changed, 319 insertions(+), 42 deletions(-) create mode 100644 packages/contracts-bedrock/test/L2/FeeSplitterVaults.t.sol create mode 100644 packages/contracts-bedrock/test/mocks/MaliciousMockFeeVault.sol create mode 100644 packages/contracts-bedrock/test/mocks/ReentrantMockFeeVault.sol diff --git a/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol b/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol index ea21661a000..4dc2ac4b476 100644 --- a/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol +++ b/packages/contracts-bedrock/interfaces/L2/IFeeSplitter.sol @@ -14,11 +14,11 @@ interface IFeeSplitter is ISemver { error FeeSplitter_NoFeesCollected(); error FeeSplitter_FeeVaultMustWithdrawToL2(); error FeeSplitter_FeeVaultMustWithdrawToFeeSplitter(); + error FeeSplitter_FeeVaultWithdrawalAmountMismatch(); error FeeSplitter_OnlyProxyAdminOwner(); error FeeSplitter_FailedToSendToRevenueShareRecipient(); error FeeSplitter_SharesCalculatorMalformedOutput(); - error FeeSplitter_ReceiveWindowClosed(); - error FeeSplitter_SenderNotApprovedVault(); + error FeeSplitter_SenderNotCurrentVault(); event FeesReceived(address indexed sender, uint256 amount, uint256 newBalance); event FeeDisbursementIntervalUpdated(uint128 oldFeeDisbursementInterval, uint128 newFeeDisbursementInterval); diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index cd6a7d7dc5b..934f3f6c50f 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -16,10 +16,6 @@ import { Preinstalls } from "src/libraries/Preinstalls.sol"; import { Types } from "src/libraries/Types.sol"; // Interfaces -import { ISequencerFeeVault } from "interfaces/L2/ISequencerFeeVault.sol"; -import { IBaseFeeVault } from "interfaces/L2/IBaseFeeVault.sol"; -import { IL1FeeVault } from "interfaces/L2/IL1FeeVault.sol"; -import { IOperatorFeeVault } from "interfaces/L2/IOperatorFeeVault.sol"; import { IOptimismMintableERC721Factory } from "interfaces/L2/IOptimismMintableERC721Factory.sol"; import { IGovernanceToken } from "interfaces/governance/IGovernanceToken.sol"; import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; diff --git a/packages/contracts-bedrock/src/L2/FeeSplitter.sol b/packages/contracts-bedrock/src/L2/FeeSplitter.sol index a616d81a265..b69b8a2691c 100644 --- a/packages/contracts-bedrock/src/L2/FeeSplitter.sol +++ b/packages/contracts-bedrock/src/L2/FeeSplitter.sol @@ -45,6 +45,9 @@ contract FeeSplitter is ISemver, Initializable { /// @notice Thrown when the FeeVault does not withdraw to FeeSplitter contract. error FeeSplitter_FeeVaultMustWithdrawToFeeSplitter(); + /// @notice Thrown when the FeeVault withdrawal amount does not match the expected amount. + error FeeSplitter_FeeVaultWithdrawalAmountMismatch(); + /// @notice Thrown when the caller is not the ProxyAdmin owner. error FeeSplitter_OnlyProxyAdminOwner(); @@ -54,16 +57,13 @@ contract FeeSplitter is ISemver, Initializable { /// @notice Thrown when the sharesCalculator returns malformed output. error FeeSplitter_SharesCalculatorMalformedOutput(); - /// @notice Thrown when receiving ETH is attempted outside of a disbursement window. - error FeeSplitter_ReceiveWindowClosed(); - - /// @notice Thrown when a sender other than an approved FeeVault attempts to send ETH. - error FeeSplitter_SenderNotApprovedVault(); + /// @notice Thrown when the sender is not the currently disbursing vault. + error FeeSplitter_SenderNotCurrentVault(); - /// @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; + /// @notice Transient storage slot key for the address of the vault currently allowed to disburse. + /// Equal to bytes32(uint256(keccak256("feesplitter.disbursingAddress")) - 1) + bytes32 internal constant _FEE_SPLITTER_DISBURSING_ADDRESS_SLOT = + 0x21346dddac42cc163a6523eefc19df981df7352c870dc3b0b17a6a92fc6fe813; /// @notice Semantic version. /// @custom:semver 1.0.0 @@ -119,14 +119,12 @@ contract FeeSplitter is ISemver, Initializable { } /// @dev Receives ETH fees withdrawn from L2 FeeVaults. - receive() external payable { - if (!_isTransientDisbursing()) revert FeeSplitter_ReceiveWindowClosed(); - if ( - msg.sender != Predeploys.SEQUENCER_FEE_WALLET && msg.sender != Predeploys.BASE_FEE_VAULT - && msg.sender != Predeploys.L1_FEE_VAULT && msg.sender != Predeploys.OPERATOR_FEE_VAULT - ) { - revert FeeSplitter_SenderNotApprovedVault(); + receive() external payable virtual { + // Sender must be the currently disbursing vault + if (msg.sender != _getTransientDisbursingAddress()) { + revert FeeSplitter_SenderNotCurrentVault(); } + uint256 newBalance = address(this).balance; emit FeesReceived(msg.sender, msg.value, newBalance); } @@ -141,12 +139,12 @@ contract FeeSplitter is ISemver, Initializable { lastDisbursementTime = uint128(block.timestamp); // Pull fees into the contract - _setTransientDisbursing(true); uint256 sequencerFees = _feeVaultWithdrawal(payable(Predeploys.SEQUENCER_FEE_WALLET)); uint256 baseFees = _feeVaultWithdrawal(payable(Predeploys.BASE_FEE_VAULT)); uint256 l1Fees = _feeVaultWithdrawal(payable(Predeploys.L1_FEE_VAULT)); uint256 operatorFees = _feeVaultWithdrawal(payable(Predeploys.OPERATOR_FEE_VAULT)); - _setTransientDisbursing(false); + // Clear the transient disbursing address + _setTransientDisbursingAddress(address(0)); uint256 grossRevenue = sequencerFees + baseFees + operatorFees + l1Fees; @@ -228,22 +226,30 @@ contract FeeSplitter is ISemver, Initializable { if (IFeeVault(_feeVault).recipient() != address(this)) { revert FeeSplitter_FeeVaultMustWithdrawToFeeSplitter(); } + + uint256 balanceBefore = address(this).balance; + _setTransientDisbursingAddress(address(_feeVault)); value_ = IFeeVault(_feeVault).withdraw(); + uint256 balanceAfter = address(this).balance; + + if (balanceAfter - balanceBefore != value_) { + revert FeeSplitter_FeeVaultWithdrawalAmountMismatch(); + } } - /// @notice Sets the transient disbursing flag. - /// @param _enabled True to enable, false to disable. - function _setTransientDisbursing(bool _enabled) internal { + /// @notice Sets the transient disbursing address. + /// @param _allowedCaller The address of the vault allowed to call receive(). + function _setTransientDisbursingAddress(address _allowedCaller) internal { assembly { - tstore(_FEE_SPLITTER_IS_DISBURSING_SLOT, _enabled) + tstore(_FEE_SPLITTER_DISBURSING_ADDRESS_SLOT, _allowedCaller) } } - /// @notice Reads the transient disbursing flag. - /// @return isDisbursing_ True if disbursement is in progress. - function _isTransientDisbursing() internal view returns (bool isDisbursing_) { + /// @notice Reads the transient disbursing address. + /// @return allowedCaller_ The address of the vault currently allowed to call receive(). + function _getTransientDisbursingAddress() internal view returns (address allowedCaller_) { assembly { - isDisbursing_ := tload(_FEE_SPLITTER_IS_DISBURSING_SLOT) + allowedCaller_ := tload(_FEE_SPLITTER_DISBURSING_ADDRESS_SLOT) } } } diff --git a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol index 387ef9f187f..04fb5663730 100644 --- a/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeSplitter.t.sol @@ -6,7 +6,9 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Mocks import { MockFeeVault } from "test/mocks/MockFeeVault.sol"; +import { MaliciousMockFeeVault } from "test/mocks/MaliciousMockFeeVault.sol"; import { RevertingRecipient } from "test/mocks/RevertingRecipient.sol"; +import { ReentrantMockFeeVault } from "test/mocks/ReentrantMockFeeVault.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -33,6 +35,9 @@ contract FeeSplitter_TestInit is CommonTest { address internal _defaultRevenueRemainderRecipient = makeAddr("RemainderRecipient"); uint128 internal _defaultFeeDisbursementInterval = 1 days; address internal _defaultSharesCalculator = makeAddr("SharesCalculator"); + address[4] internal _feeVaults; + bytes32 internal constant _FEE_SPLITTER_DISBURSING_ADDRESS_SLOT = + 0x21346dddac42cc163a6523eefc19df981df7352c870dc3b0b17a6a92fc6fe813; /// @notice Test setup. function setUp() public virtual override { @@ -42,6 +47,12 @@ contract FeeSplitter_TestInit is CommonTest { // Get the owner from ProxyAdmin _owner = IProxyAdmin(Predeploys.PROXY_ADMIN).owner(); + + // Initialize fee vaults array + _feeVaults[0] = Predeploys.SEQUENCER_FEE_WALLET; + _feeVaults[1] = Predeploys.BASE_FEE_VAULT; + _feeVaults[2] = Predeploys.L1_FEE_VAULT; + _feeVaults[3] = Predeploys.OPERATOR_FEE_VAULT; } /// @notice Helper function to setup a mock and expect a call to it. @@ -140,12 +151,16 @@ contract FeeSplitter_Initialize_Test is FeeSplitter_TestInit { /// @title FeeSplitter_Receive_Test /// @notice Tests the receive function of the `FeeSplitter` contract. 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 { + /// @notice Test that receive function reverts when sender is not an approved vault + function testFuzz_feeSplitterReceive_whenNotApprovedVault_reverts(address _caller, uint256 _amount) public { + vm.assume(_caller != Predeploys.SEQUENCER_FEE_WALLET); + vm.assume(_caller != Predeploys.BASE_FEE_VAULT); + vm.assume(_caller != Predeploys.OPERATOR_FEE_VAULT); + vm.assume(_caller != Predeploys.L1_FEE_VAULT); vm.deal(_caller, _amount); vm.prank(_caller); - vm.expectRevert(IFeeSplitter.FeeSplitter_ReceiveWindowClosed.selector); + vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotCurrentVault.selector); payable(address(feeSplitter)).call{ value: _amount }(""); } @@ -161,12 +176,12 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { vm.startPrank(_caller); // Now we test the actual sender validation - vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotApprovedVault.selector); + vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotCurrentVault.selector); payable(address(feeSplitter)).call{ value: _amount }(""); } /// @notice Test receive function works during disbursement from SequencerFeeVault - function test_feeSplitterReceive_sequencerFeeVault_succeeds(uint256 _amount) public { + function testFuzz_feeSplitterReceive_sequencerFeeVault_succeeds(uint256 _amount) public { _amount = bound(_amount, 1, type(uint256).max); // Setup mocks - only sequencer vault has balance @@ -203,7 +218,7 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { } /// @notice Test receive function works during disbursement from BaseFeeVault - function test_feeSplitterReceive_baseFeeVault_succeeds(uint256 _amount) public { + function testFuzz_feeSplitterReceive_baseFeeVault_succeeds(uint256 _amount) public { _amount = bound(_amount, 1, type(uint256).max); // Setup mocks - only sequencer vault has balance @@ -240,7 +255,7 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { } /// @notice Test receive function works during disbursement from L1FeeVault - function test_feeSplitterReceive_l1FeeVault_succeeds(uint256 _amount) public { + function testFuzz_feeSplitterReceive_l1FeeVault_succeeds(uint256 _amount) public { _amount = bound(_amount, 1, type(uint256).max); // Setup mocks - only sequencer vault has balance @@ -277,7 +292,7 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { } /// @notice Test receive function works during disbursement from OperatorFeeVault - function test_feeSplitterReceive_operatorFeeVault_succeeds(uint256 _amount) public { + function testFuzz_feeSplitterReceive_operatorFeeVault_succeeds(uint256 _amount) public { _amount = bound(_amount, 1, type(uint256).max); // Setup mocks - only sequencer vault has balance @@ -312,6 +327,34 @@ contract FeeSplitter_Receive_Test is FeeSplitter_TestInit { assertEq(address(feeSplitter).balance, 0); assertEq(feeSplitter.lastDisbursementTime(), block.timestamp); } + + /// @notice Test that a malicious vault cannot trigger withdrawals from other vaults during its own withdrawal. + /// This test demonstrates that the stricter receive() validation (checking the specific vault address) + /// prevents a re-entrancy attack where one vault tries to indirectly call withdraw() on a different vault. + function test_feeSplitterReceive_reentrantVaultAttack_reverts() public { + uint256 sequencerAmount = 1 ether; + uint256 baseAmount = 2 ether; + + // Setup SEQUENCER_FEE_WALLET as a malicious vault that will try to trigger BASE_FEE_VAULT withdrawal + ReentrantMockFeeVault maliciousVault = new ReentrantMockFeeVault( + payable(address(feeSplitter)), sequencerAmount, payable(Predeploys.BASE_FEE_VAULT) + ); + + vm.etch(Predeploys.SEQUENCER_FEE_WALLET, address(maliciousVault).code); + vm.deal(Predeploys.SEQUENCER_FEE_WALLET, sequencerAmount); + + // Fast forward time + vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + + // Expect the disbursement to revert with the MockFeeVault error message. + // The flow is: + // 1. FeeSplitter:disburseFees() is called + // 2. Splitter triggers withdrawal from SEQUENCER_FEE_WALLET (etched with malicious code) + // 3. SEQUENCER_FEE_WALLET sends ETH to FeeSplitter and triggers withdrawal from BASE_FEE_VAULT + // 4. BASE_FEE_VAULT's withdraw() reverts with the FeeVault's error message + vm.expectRevert("FeeVault: failed to send ETH to L2 fee recipient"); + feeSplitter.disburseFees(); + } } /// @title FeeSplitter_DisburseFees_Test @@ -366,6 +409,34 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { feeSplitter.disburseFees(); } + /// @notice Test disburseFees reverts when fee vault withdrawal amount does not match the expected amount + function testFuzz_feeSplitterDisburseFees_whenFeeVaultWithdrawalAmountMismatch_reverts( + uint256 _actualTransferAmount, + uint256 _claimedWithdrawalAmount + ) + public + { + vm.assume(_actualTransferAmount != _claimedWithdrawalAmount); + + // Create a malicious mock vault that lies about withdrawal amount + MaliciousMockFeeVault maliciousVault = + new MaliciousMockFeeVault(payable(address(feeSplitter)), _actualTransferAmount, _claimedWithdrawalAmount); + vm.deal(address(maliciousVault), _actualTransferAmount); + + // Replace SEQUENCER_FEE_WALLET with the malicious vault + vm.etch(Predeploys.SEQUENCER_FEE_WALLET, address(maliciousVault).code); + vm.deal(Predeploys.SEQUENCER_FEE_WALLET, _actualTransferAmount); + + // Setup other vaults normally with zero balance + _mockFeeVaultForSuccessfulWithdrawal(Predeploys.BASE_FEE_VAULT, 0); + _mockFeeVaultForSuccessfulWithdrawal(Predeploys.L1_FEE_VAULT, 0); + _mockFeeVaultForSuccessfulWithdrawal(Predeploys.OPERATOR_FEE_VAULT, 0); + + vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + vm.expectRevert(IFeeSplitter.FeeSplitter_FeeVaultWithdrawalAmountMismatch.selector); + feeSplitter.disburseFees(); + } + /// @notice Test successful fee disbursement with fixed amounts function test_feeSplitterDisburseFees_succeeds() public { uint256 _sequencerAmount = 2 ether; @@ -489,7 +560,12 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { } /// @notice Fuzz test that a vault with balance below minimum causes entire disbursement to revert - function test_disburseFees_vaultBelowMinimum_reverts(uint256 _minWithdrawalAmount, uint256 _vaultIndex) public { + function testFuzz_disburseFees_vaultBelowMinimum_reverts( + uint256 _minWithdrawalAmount, + uint256 _vaultIndex + ) + public + { // If uint256, the test will revert due to ETH transfer overflow _minWithdrawalAmount = bound(_minWithdrawalAmount, 1, type(uint128).max); _vaultIndex = bound(_vaultIndex, 0, 3); // 0-3 for the 4 vaults @@ -533,6 +609,59 @@ contract FeeSplitter_DisburseFees_Test is FeeSplitter_TestInit { vm.etch(_vault, address(mockVault).code); vm.deal(_vault, _balance); } + + /// @notice Test that vaults cannot send ETH after disburseFees completes (transient storage cleanup check) + /// @param _vaultIndex The index of the vault to test (0-3). + function testFuzz_feeSplitterDisburseFees_vaultsCannotSendAfterDisbursement_reverts(uint256 _vaultIndex) public { + _vaultIndex = bound(_vaultIndex, 0, 3); + + uint256 _sequencerAmount = 2 ether; + uint256 _baseAmount = 3 ether; + uint256 _l1Amount = 1 ether; + uint256 _operatorAmount = 4 ether; + + _setupStandardFeeVaultMocks(_sequencerAmount, _baseAmount, _l1Amount, _operatorAmount); + + // Calculate expected gross revenue + uint256 expectedGrossRevenue = _sequencerAmount + _baseAmount + _l1Amount + _operatorAmount; + + // Setup mock shares calculator to return 50/50 split + uint256 halfGrossRevenue = expectedGrossRevenue / 2; + ISharesCalculator.ShareInfo[] memory expectedShareInfo = new ISharesCalculator.ShareInfo[](2); + expectedShareInfo[0] = ISharesCalculator.ShareInfo(payable(_defaultRevenueShareRecipient), halfGrossRevenue); + expectedShareInfo[1] = ISharesCalculator.ShareInfo( + payable(_defaultRevenueRemainderRecipient), expectedGrossRevenue - halfGrossRevenue + ); + + // Get the actual shares calculator from the FeeSplitter + address actualSharesCalculator = address(feeSplitter.sharesCalculator()); + vm.mockCall( + actualSharesCalculator, + abi.encodeCall( + ISharesCalculator.getRecipientsAndAmounts, (_sequencerAmount, _baseAmount, _operatorAmount, _l1Amount) + ), + abi.encode(expectedShareInfo) + ); + + // Fast forward time to allow disbursement + vm.warp(block.timestamp + feeSplitter.feeDisbursementInterval() + 1); + + // Call disburseFees + feeSplitter.disburseFees(); + + // Verify disbursement was successful + assertEq(feeSplitter.lastDisbursementTime(), block.timestamp); + + // Now try to send ETH from one of the vaults after disbursement + address _vault = _feeVaults[_vaultIndex]; + uint256 _attemptAmount = 1 ether; + vm.deal(_vault, _attemptAmount); + + // Attempt to send ETH from the vault - should revert because transient storage was cleared + vm.prank(_vault); + vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotCurrentVault.selector); + payable(address(feeSplitter)).call{ value: _attemptAmount }(""); + } } /// @title FeeSplitter_SetSharesCalculator_Test diff --git a/packages/contracts-bedrock/test/L2/FeeSplitterVaults.t.sol b/packages/contracts-bedrock/test/L2/FeeSplitterVaults.t.sol new file mode 100644 index 00000000000..af1dfdabe08 --- /dev/null +++ b/packages/contracts-bedrock/test/L2/FeeSplitterVaults.t.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +// Contracts +import { FeeSplitter } from "src/L2/FeeSplitter.sol"; + +// Libraries +import { Predeploys } from "src/libraries/Predeploys.sol"; + +// Testing +import { Test } from "forge-std/Test.sol"; + +// Interfaces +import { IFeeSplitter } from "interfaces/L2/IFeeSplitter.sol"; + +/// @title FeeSplitterForTest +/// @notice Test contract for the FeeSplitter contract. +/// @dev Makes the setTransientDisbursingAddress function public for testing purposes. +contract FeeSplitterForTest is FeeSplitter { + function setTransientDisbursingAddress(address _allowedCaller) external { + _setTransientDisbursingAddress(_allowedCaller); + } +} + +/// @title FeeSplitterVaults_Test +/// @notice Test contract for the FeeSplitter contract with vaults. +/// @dev This test is done in a different file given we need the 0.8.25 compiler version to import the FeeSplitter +/// implementation and modify it. +contract FeeSplitterVaults_Test is Test { + FeeSplitterForTest feeSplitter; + address[4] internal _feeVaults; + + function setUp() public { + FeeSplitterForTest feeSplitterImpl = new FeeSplitterForTest(); + feeSplitter = FeeSplitterForTest(payable(Predeploys.FEE_SPLITTER)); + + vm.etch(Predeploys.FEE_SPLITTER, address(feeSplitterImpl).code); + vm.etch(Predeploys.SEQUENCER_FEE_WALLET, vm.getDeployedCode("SequencerFeeVault.sol")); + vm.etch(Predeploys.BASE_FEE_VAULT, vm.getDeployedCode("BaseFeeVault.sol")); + vm.etch(Predeploys.OPERATOR_FEE_VAULT, vm.getDeployedCode("OperatorFeeVault.sol")); + vm.etch(Predeploys.L1_FEE_VAULT, vm.getDeployedCode("L1FeeVault.sol")); + + _feeVaults[0] = Predeploys.SEQUENCER_FEE_WALLET; + _feeVaults[1] = Predeploys.BASE_FEE_VAULT; + _feeVaults[2] = Predeploys.OPERATOR_FEE_VAULT; + _feeVaults[3] = Predeploys.L1_FEE_VAULT; + } + + /// @notice Test that receive function reverts when sender is an approved vault but not currently disbursing + /// @param _amount The amount of ETH to send. + /// @dev This test simulates the disbursement context on each vault and then goes + /// through each vault and sends ETH to the fee splitter, expecting the receive function to revert + function testFuzz_feeSplitterReceive_whenNotCurrentVault_reverts(uint128 _amount) public { + for (uint256 i = 0; i < _feeVaults.length; i++) { + address _disbursingVault = _feeVaults[i]; + feeSplitter.setTransientDisbursingAddress(_disbursingVault); + for (uint256 j = 0; j < _feeVaults.length; j++) { + address _selectedVault = _feeVaults[j]; + vm.deal(_selectedVault, _amount); + + if (_selectedVault != _disbursingVault) { + vm.expectRevert(IFeeSplitter.FeeSplitter_SenderNotCurrentVault.selector); + } + + vm.prank(_selectedVault); + payable(address(feeSplitter)).call{ value: _amount }(""); + } + } + } +} diff --git a/packages/contracts-bedrock/test/L2/FeeVault.t.sol b/packages/contracts-bedrock/test/L2/FeeVault.t.sol index 1cfee1b57ea..edbd1c0064d 100644 --- a/packages/contracts-bedrock/test/L2/FeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/FeeVault.t.sol @@ -68,7 +68,7 @@ abstract contract FeeVault_Uncategorized_Test is CommonTest { /// @notice Tests that `withdraw` reverts if the balance is less than the minimum withdrawal /// amount. - function test_withdraw_notEnough_reverts(uint256 _minWithdrawalAmount) external { + function testFuzz_withdraw_notEnough_reverts(uint256 _minWithdrawalAmount) external { // Set the minimum withdrawal amount _minWithdrawalAmount = bound(_minWithdrawalAmount, 1, type(uint256).max); vm.prank(IProxyAdmin(Predeploys.PROXY_ADMIN).owner()); diff --git a/packages/contracts-bedrock/test/mocks/MaliciousMockFeeVault.sol b/packages/contracts-bedrock/test/mocks/MaliciousMockFeeVault.sol new file mode 100644 index 00000000000..92816438c49 --- /dev/null +++ b/packages/contracts-bedrock/test/mocks/MaliciousMockFeeVault.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { Types } from "src/libraries/Types.sol"; + +/// @notice Mock fee vault that returns a different withdrawal amount than what it transfers +contract MaliciousMockFeeVault { + address public immutable RECIPIENT; + uint256 public immutable ACTUAL_TRANSFER_AMOUNT; + uint256 public immutable CLAIMED_WITHDRAWAL_AMOUNT; + + constructor(address payable _recipient, uint256 _actualTransferAmount, uint256 _claimedWithdrawalAmount) { + RECIPIENT = _recipient; + ACTUAL_TRANSFER_AMOUNT = _actualTransferAmount; + CLAIMED_WITHDRAWAL_AMOUNT = _claimedWithdrawalAmount; + } + + receive() external payable { } + + function withdrawalNetwork() external pure returns (Types.WithdrawalNetwork) { + return Types.WithdrawalNetwork.L2; + } + + function recipient() external view returns (address) { + return RECIPIENT; + } + + function withdraw() external returns (uint256) { + // Transfer the actual amount + (bool success,) = RECIPIENT.call{ value: ACTUAL_TRANSFER_AMOUNT }(""); + require(success, "MaliciousMockFeeVault: failed to send ETH"); + + // But lie about how much was transferred + return CLAIMED_WITHDRAWAL_AMOUNT; + } +} diff --git a/packages/contracts-bedrock/test/mocks/ReentrantMockFeeVault.sol b/packages/contracts-bedrock/test/mocks/ReentrantMockFeeVault.sol new file mode 100644 index 00000000000..dc2b4916c90 --- /dev/null +++ b/packages/contracts-bedrock/test/mocks/ReentrantMockFeeVault.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { Types } from "src/libraries/Types.sol"; +import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; + +/// @notice Mock fee vault that attempts to trigger withdrawal from a different vault during its own withdrawal. +/// This demonstrates the attack vector where a malicious vault tries to exploit the disbursing context +/// to allow unauthorized withdrawals from other vaults. +contract ReentrantMockFeeVault { + address public immutable RECIPIENT; + uint256 public immutable WITHDRAWAL_AMOUNT; + address payable public immutable TARGET_VAULT; + + constructor(address payable _recipient, uint256 _withdrawalAmount, address payable _targetVault) { + RECIPIENT = _recipient; + WITHDRAWAL_AMOUNT = _withdrawalAmount; + TARGET_VAULT = _targetVault; + } + + receive() external payable { } + + function withdrawalNetwork() external pure returns (Types.WithdrawalNetwork) { + return Types.WithdrawalNetwork.L2; + } + + function recipient() external view returns (address) { + return RECIPIENT; + } + + function withdraw() external returns (uint256) { + // Attempt to trigger a withdrawal from a different vault + // This should fail with the new stricter check and propagate the revert + if (TARGET_VAULT != address(0)) { + IFeeVault(TARGET_VAULT).withdraw(); + } + + return WITHDRAWAL_AMOUNT; + } +}