From b9aa0c054cb8aadaa340cf29082c4ec008124f0d Mon Sep 17 00:00:00 2001 From: John Letey Date: Wed, 4 Mar 2026 15:00:00 +0100 Subject: [PATCH 1/4] feat(interfaces): add fee recipient support to `IValidatorManager` --- src/interfaces/IValidatorManager.sol | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/interfaces/IValidatorManager.sol b/src/interfaces/IValidatorManager.sol index 21770b0..f5669a0 100644 --- a/src/interfaces/IValidatorManager.sol +++ b/src/interfaces/IValidatorManager.sol @@ -16,6 +16,7 @@ interface IValidatorManager { uint32 ip; uint16 port; bytes32 publicKey; + address feeRecipient; bytes32 name; } @@ -23,6 +24,7 @@ interface IValidatorManager { struct ValidatorInfo { uint64 index; bytes32 publicKey; + address feeRecipient; string name; string socketAddress; } @@ -30,6 +32,7 @@ interface IValidatorManager { /// @notice Input struct for genesis validators. struct GenesisValidator { bytes32 publicKey; + address feeRecipient; bytes32 name; uint32 ip; uint16 port; @@ -45,10 +48,16 @@ interface IValidatorManager { /// @notice Emitted when a validator is removed. event ValidatorRemoved(uint64 indexed index, bytes32 indexed publicKey, string name, uint64 epochRemoved); + /// @notice Emitted when a validator's fee recipient is updated. + event FeeRecipientUpdated(bytes32 indexed publicKey, address oldFeeRecipient, address newFeeRecipient); + // ========================================================================= // Errors // ========================================================================= + /// @notice Error when the caller is not authorized. + error Unauthorized(); + /// @notice Error when a validator is already added. error ValidatorAlreadyAdded(bytes32 publicKey); @@ -64,15 +73,25 @@ interface IValidatorManager { /// @notice Adds a new validator to the set, applied from the next epoch. /// @param publicKey The validator's public key. + /// @param feeRecipient The address that receives fees on behalf of the validator. /// @param name The validator's name. /// @param ip The validator's IPv4 address. /// @param port The validator's port. - function addValidator(bytes32 publicKey, bytes32 name, uint32 ip, uint16 port) external; + function addValidator(bytes32 publicKey, address feeRecipient, bytes32 name, uint32 ip, uint16 port) external; /// @notice Removes a validator from the set, applied from the next epoch. /// @param publicKey The validator's public key. function removeValidator(bytes32 publicKey) external; + /// @notice Updates the fee recipient address for a validator. + /// @param publicKey The validator's public key. + /// @param feeRecipient The new address that receives fees on behalf of the validator. + function setFeeRecipient(bytes32 publicKey, address feeRecipient) external; + + /// @notice Returns the fee recipient address for a validator. + /// @param publicKey The validator's public key. + function getFeeRecipient(bytes32 publicKey) external view returns (address); + /// @notice Returns validators active in the current epoch. function getCurrentValidators() external view returns (ValidatorInfo[] memory); From a13eccbb86656b49f5f9713f335e9fd8210fb756 Mon Sep 17 00:00:00 2001 From: John Letey Date: Thu, 5 Mar 2026 11:27:42 +0100 Subject: [PATCH 2/4] feat(interfaces): add `IFeeDistributor` --- src/interfaces/IFeeDistributor.sol | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/interfaces/IFeeDistributor.sol diff --git a/src/interfaces/IFeeDistributor.sol b/src/interfaces/IFeeDistributor.sol new file mode 100644 index 0000000..0b332e0 --- /dev/null +++ b/src/interfaces/IFeeDistributor.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity >=0.8.13 <0.9.0; + +/// @title IFeeDistributor +/// @notice Interface for the Fee Distributor contract. +interface IFeeDistributor { + // ========================================================================= + // Types + // ========================================================================= + + /// @notice Return struct for recipient information. + struct RecipientInfo { + address recipient; + uint16 bps; + } + + // ========================================================================= + // Events + // ========================================================================= + + /// @notice Emitted when a recipient is added or updated. + /// @param recipient The recipient address. + /// @param bps The new share of fees in basis points. + event RecipientSet(address indexed recipient, uint16 bps); + + /// @notice Emitted when a recipient is removed. + /// @param recipient The recipient address. + event RecipientRemoved(address indexed recipient); + + // ========================================================================= + // Errors + // ========================================================================= + + /// @notice Error when the caller is not authorized. + error Unauthorized(); + + /// @notice Error when zero basis points is provided. + error ZeroBps(); + + /// @notice Error when total basis points exceeds 10,000. + error TotalBpsExceeded(uint16 totalBps); + + /// @notice Error when the recipient does not exist. + error RecipientNotFound(address recipient); + + // ========================================================================= + // Functions + // ========================================================================= + + /// @notice Sets or updates a recipient's share in basis points. + /// @param recipient The address to receive fees. + /// @param bps The share of fees in basis points. + function setRecipient(address recipient, uint16 bps) external; + + /// @notice Removes a recipient from fee distribution. + /// @param recipient The address to remove. + function removeRecipient(address recipient) external; + + /// @notice Distributes the contract's native balance to recipients. + /// @dev Called during block finalization outside of the normal transaction + /// lifecycle. Implementations must not revert. Each recipient receives a + /// portion of the balance according to their configured basis points. Any + /// remainder is sent to the current block proposer's fee recipient address. + function distribute() external; + + /// @notice Returns all current recipients and their basis points. + /// @return recipients The array of recipient addresses and their shares. + function getRecipients() external view returns (RecipientInfo[] memory recipients); +} From 9bd3f09c17506356fde31ad98d4966b9373d6e9d Mon Sep 17 00:00:00 2001 From: John Letey Date: Thu, 5 Mar 2026 11:29:00 +0100 Subject: [PATCH 3/4] chore(constants): add `FeeDistributor` address --- src/Constants.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Constants.sol b/src/Constants.sol index 55657bf..b7a7f9f 100644 --- a/src/Constants.sol +++ b/src/Constants.sol @@ -15,3 +15,6 @@ address constant VALIDATOR_MANAGER_ADDRESS = 0x662530000000000000000000000000000 /// @dev The address of the Registrar predeployed contract on Noble. address constant REGISTRAR_ADDRESS = 0x6625300000000000000000000000000000000003; + +/// @dev The address of the FeeDistributor predeployed contract on Noble. +address constant FEE_DISTRIBUTOR_ADDRESS = 0x6625300000000000000000000000000000000004; From dcc483fadf995032e85d527644be7af51661f5f5 Mon Sep 17 00:00:00 2001 From: Sebastian Pusch Date: Tue, 10 Mar 2026 10:23:42 +0100 Subject: [PATCH 4/4] feat: add ZeroAddress error to IValidatorManager --- src/interfaces/IValidatorManager.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interfaces/IValidatorManager.sol b/src/interfaces/IValidatorManager.sol index f5669a0..cd0c69e 100644 --- a/src/interfaces/IValidatorManager.sol +++ b/src/interfaces/IValidatorManager.sol @@ -67,6 +67,9 @@ interface IValidatorManager { /// @notice Error when a validator does not exist. error ValidatorNotFound(bytes32 publicKey); + /// @notice Error when an address is the zero address. + error ZeroAddress(); + // ========================================================================= // Functions // =========================================================================