Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"lib/eigenlayer-middleware/src/IndexRegistry.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {IIndexRegistry, IndexRegistryStorage} from "./IndexRegistryStorage.sol";
import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol";
/**
* @title A `Registry` that keeps track of an ordered list of operators for each quorum
* @author Layr Labs, Inc.
*/
contract IndexRegistry is IndexRegistryStorage {
modifier onlyRegistryCoordinator() {
_checkRegistryCoordinator();
_;
}
constructor(
ISlashingRegistryCoordinator _slashingRegistryCoordinator
) IndexRegistryStorage(_slashingRegistryCoordinator) {}
/**
*
* EXTERNAL FUNCTIONS - REGISTRY COORDINATOR
*
*/
/// @inheritdoc IIndexRegistry
function registerOperator(
bytes32 operatorId,
bytes calldata quorumNumbers
) public virtual onlyRegistryCoordinator returns (uint32[] memory) {
uint32[] memory numOperatorsPerQuorum = new uint32[](quorumNumbers.length);
for (uint256 i = 0; i < quorumNumbers.length; i++) {
// Validate quorum exists and get current operator count
uint8 quorumNumber = uint8(quorumNumbers[i]);
uint256 historyLength = _operatorCountHistory[quorumNumber].length;
require(historyLength != 0, QuorumDoesNotExist());
/**
* Increase the number of operators currently active for this quorum,
* and assign the operator to the last operatorIndex available
*/
uint32 newOperatorCount = _increaseOperatorCount(quorumNumber);
_assignOperatorToIndex({
operatorId: operatorId,
quorumNumber: quorumNumber,
operatorIndex: newOperatorCount - 1
});
// Record the current operator count for each quorum
numOperatorsPerQuorum[i] = newOperatorCount;
}
return numOperatorsPerQuorum;
}
/// @inheritdoc IIndexRegistry
function deregisterOperator(
bytes32 operatorId,
bytes calldata quorumNumbers
) public virtual onlyRegistryCoordinator {
for (uint256 i = 0; i < quorumNumbers.length; i++) {
// Validate quorum exists and get the operatorIndex of the operator being deregistered
uint8 quorumNumber = uint8(quorumNumbers[i]);
uint256 historyLength = _operatorCountHistory[quorumNumber].length;
require(historyLength != 0, QuorumDoesNotExist());
uint32 operatorIndexToRemove = currentOperatorIndex[quorumNumber][operatorId];
/**
* "Pop" the operator from the registry:
* 1. Decrease the operator count for the quorum
* 2. Remove the last operator associated with the count
* 3. Place the last operator in the deregistered operator's old position
*/
uint32 newOperatorCount = _decreaseOperatorCount(quorumNumber);
bytes32 lastOperatorId = _popLastOperator(quorumNumber, newOperatorCount);
if (operatorId != lastOperatorId) {
_assignOperatorToIndex({
operatorId: lastOperatorId,
quorumNumber: quorumNumber,
operatorIndex: operatorIndexToRemove
});
}
}
}
/// @inheritdoc IIndexRegistry
function initializeQuorum(
uint8 quorumNumber
) public virtual onlyRegistryCoordinator {
require(_operatorCountHistory[quorumNumber].length == 0, QuorumDoesNotExist());
_operatorCountHistory[quorumNumber].push(
QuorumUpdate({numOperators: 0, fromBlockNumber: uint32(block.number)})
);
}
/**
*
* INTERNAL FUNCTIONS
*
*/
/// @notice Increases the historical operator count by 1 and returns the new count.
function _increaseOperatorCount(
uint8 quorumNumber
) internal returns (uint32) {
QuorumUpdate storage lastUpdate = _latestQuorumUpdate(quorumNumber);
uint32 newOperatorCount = lastUpdate.numOperators + 1;
_updateOperatorCountHistory(quorumNumber, lastUpdate, newOperatorCount);
// If this is the first time we're using this operatorIndex, push its first update
// This maintains an invariant: existing indices have nonzero history
if (_operatorIndexHistory[quorumNumber][newOperatorCount - 1].length == 0) {
_operatorIndexHistory[quorumNumber][newOperatorCount - 1].push(
OperatorUpdate({
operatorId: OPERATOR_DOES_NOT_EXIST_ID,
fromBlockNumber: uint32(block.number)
})
);
}
return newOperatorCount;
}
/// @notice Decreases the historical operator count by 1 and returns the new count.
function _decreaseOperatorCount(
uint8 quorumNumber
) internal returns (uint32) {
QuorumUpdate storage lastUpdate = _latestQuorumUpdate(quorumNumber);
uint32 newOperatorCount = lastUpdate.numOperators - 1;
_updateOperatorCountHistory(quorumNumber, lastUpdate, newOperatorCount);
return newOperatorCount;
}
/// @notice Updates `_operatorCountHistory` with a new operator count.
/// @dev If the lastUpdate was made in this block, update the entry.
/// Otherwise, push a new historical entry.
function _updateOperatorCountHistory(
uint8 quorumNumber,
QuorumUpdate storage lastUpdate,
uint32 newOperatorCount
) internal {
if (lastUpdate.fromBlockNumber == uint32(block.number)) {
lastUpdate.numOperators = newOperatorCount;
} else {
_operatorCountHistory[quorumNumber].push(
QuorumUpdate({numOperators: newOperatorCount, fromBlockNumber: uint32(block.number)})
);
}
}
/// @notice For a given quorum and operatorIndex, pop and return the last operatorId in the history.
/// @dev The last entry's operatorId is updated to OPERATOR_DOES_NOT_EXIST_ID.
/// @return The removed operatorId.
function _popLastOperator(
uint8 quorumNumber,
uint32 operatorIndex
) internal returns (bytes32) {
OperatorUpdate storage lastUpdate = _latestOperatorIndexUpdate(quorumNumber, operatorIndex);
bytes32 removedOperatorId = lastUpdate.operatorId;
// Set the current operator id for this operatorIndex to 0
_updateOperatorIndexHistory(
quorumNumber, operatorIndex, lastUpdate, OPERATOR_DOES_NOT_EXIST_ID
);
return removedOperatorId;
}
/// @notice Assigns an operator to an index and updates the index history.
/// @param operatorId operatorId of the operator to update.
/// @param quorumNumber quorumNumber of the operator to update.
/// @param operatorIndex the latest index of that operator in the list of operators registered for this quorum.
function _assignOperatorToIndex(
bytes32 operatorId,
uint8 quorumNumber,
uint32 operatorIndex
) internal {
OperatorUpdate storage lastUpdate = _latestOperatorIndexUpdate(quorumNumber, operatorIndex);
_updateOperatorIndexHistory(quorumNumber, operatorIndex, lastUpdate, operatorId);
// Assign the operator to their new current operatorIndex
currentOperatorIndex[quorumNumber][operatorId] = operatorIndex;
emit QuorumIndexUpdate(operatorId, quorumNumber, operatorIndex);
}
/// @notice Updates `_operatorIndexHistory` with a new operator id for the current block.
/// @dev If the lastUpdate was made in this block, update the entry.
/// Otherwise, push a new historical entry.
function _updateOperatorIndexHistory(
uint8 quorumNumber,
uint32 operatorIndex,
OperatorUpdate storage lastUpdate,
bytes32 newOperatorId
) internal {
if (lastUpdate.fromBlockNumber == uint32(block.number)) {
lastUpdate.operatorId = newOperatorId;
} else {
_operatorIndexHistory[quorumNumber][operatorIndex].push(
OperatorUpdate({operatorId: newOperatorId, fromBlockNumber: uint32(block.number)})
);
}
}
/// @notice Returns the most recent operator count update for a quorum.
/// @dev Reverts if the quorum does not exist (history length == 0).
function _latestQuorumUpdate(
uint8 quorumNumber
) internal view returns (QuorumUpdate storage) {
uint256 historyLength = _operatorCountHistory[quorumNumber].length;
return _operatorCountHistory[quorumNumber][historyLength - 1];
}
/// @notice Returns the most recent operator id update for an index.
/// @dev Reverts if the index has never been used (history length == 0).
function _latestOperatorIndexUpdate(
uint8 quorumNumber,
uint32 operatorIndex
) internal view returns (OperatorUpdate storage) {
uint256 historyLength = _operatorIndexHistory[quorumNumber][operatorIndex].length;
return _operatorIndexHistory[quorumNumber][operatorIndex][historyLength - 1];
}
/// @notice Returns the total number of operators of the service for the given `quorumNumber` at the given `blockNumber`.
/// @dev Reverts if the quorum does not exist, or if the blockNumber is from before the quorum existed.
function _operatorCountAtBlockNumber(
uint8 quorumNumber,
uint32 blockNumber
) internal view returns (uint32) {
uint256 historyLength = _operatorCountHistory[quorumNumber].length;
// Loop backwards through _operatorCountHistory until we find an entry that preceeds `blockNumber`
for (uint256 i = historyLength; i > 0; i--) {
QuorumUpdate memory quorumUpdate = _operatorCountHistory[quorumNumber][i - 1];
if (quorumUpdate.fromBlockNumber <= blockNumber) {
return quorumUpdate.numOperators;
}
}
revert(
"IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"
);
}
/// @notice Returns the operatorId at the given `operatorIndex` at the given `blockNumber` for the given `quorumNumber`.
/// @dev Requires that the operatorIndex was active at the given block number for quorum.
function _operatorIdForIndexAtBlockNumber(
uint8 quorumNumber,
uint32 operatorIndex,
uint32 blockNumber
) internal view returns (bytes32) {
uint256 historyLength = _operatorIndexHistory[quorumNumber][operatorIndex].length;
// Loop backward through _operatorIndexHistory until we find an entry that preceeds `blockNumber`
for (uint256 i = historyLength; i > 0; i--) {
OperatorUpdate memory operatorIndexUpdate =
_operatorIndexHistory[quorumNumber][operatorIndex][i - 1];
if (operatorIndexUpdate.fromBlockNumber <= blockNumber) {
// Special case: this will be OPERATOR_DOES_NOT_EXIST_ID if this operatorIndex was not used at the block number
return operatorIndexUpdate.operatorId;
}
}
// we should only hit this if the operatorIndex was never used before blockNumber
return OPERATOR_DOES_NOT_EXIST_ID;
}
/**
*
* VIEW FUNCTIONS
*
*/
/// @inheritdoc IIndexRegistry
function getOperatorUpdateAtIndex(
uint8 quorumNumber,
uint32 operatorIndex,
uint32 arrayIndex
) external view returns (OperatorUpdate memory) {
return _operatorIndexHistory[quorumNumber][operatorIndex][arrayIndex];
}
/// @inheritdoc IIndexRegistry
function getQuorumUpdateAtIndex(
uint8 quorumNumber,
uint32 quorumIndex
) external view returns (QuorumUpdate memory) {
return _operatorCountHistory[quorumNumber][quorumIndex];
}
/// @inheritdoc IIndexRegistry
function getLatestQuorumUpdate(
uint8 quorumNumber
) external view returns (QuorumUpdate memory) {
return _latestQuorumUpdate(quorumNumber);
}
/// @inheritdoc IIndexRegistry
function getLatestOperatorUpdate(
uint8 quorumNumber,
uint32 operatorIndex
) external view returns (OperatorUpdate memory) {
return _latestOperatorIndexUpdate(quorumNumber, operatorIndex);
}
/// @inheritdoc IIndexRegistry
function getOperatorListAtBlockNumber(
uint8 quorumNumber,
uint32 blockNumber
) external view returns (bytes32[] memory) {
uint32 operatorCount = _operatorCountAtBlockNumber(quorumNumber, blockNumber);
bytes32[] memory operatorList = new bytes32[](operatorCount);
for (uint256 i = 0; i < operatorCount; i++) {
operatorList[i] = _operatorIdForIndexAtBlockNumber(quorumNumber, uint32(i), blockNumber);
require(operatorList[i] != OPERATOR_DOES_NOT_EXIST_ID, OperatorIdDoesNotExist());
}
return operatorList;
}
/// @inheritdoc IIndexRegistry
function totalOperatorsForQuorum(
uint8 quorumNumber
) external view returns (uint32) {
return _latestQuorumUpdate(quorumNumber).numOperators;
}
function _checkRegistryCoordinator() internal view {
require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinator());
}
}
"
},
"lib/eigenlayer-middleware/src/IndexRegistryStorage.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol";
import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol";
/**
* @title Storage variables for the `IndexRegistry` contract.
* @author Layr Labs, Inc.
* @notice This storage contract is separate from the logic to simplify the upgrade process.
*/
abstract contract IndexRegistryStorage is Initializable, IIndexRegistry {
/// @notice The value that is returned when an operator does not exist at an index at a certain block
bytes32 public constant OPERATOR_DOES_NOT_EXIST_ID = bytes32(0);
/// @notice The RegistryCoordinator contract for this middleware
address public immutable registryCoordinator;
/// @notice maps quorumNumber => operator id => current operatorIndex
/// NOTE: This mapping is NOT updated when an operator is deregistered,
/// so it's possible that an index retrieved from this mapping is inaccurate.
/// If you're querying for an operator that might be deregistered, ALWAYS
/// check this index against the latest `_operatorIndexHistory` entry
mapping(uint8 => mapping(bytes32 => uint32)) public currentOperatorIndex;
/// @notice maps quorumNumber => operatorIndex => historical operator ids at that index
mapping(uint8 => mapping(uint32 => OperatorUpdate[])) internal _operatorIndexHistory;
/// @notice maps quorumNumber => historical number of unique registered operators
mapping(uint8 => QuorumUpdate[]) internal _operatorCountHistory;
constructor(
ISlashingRegistryCoordinator _slashingRegistryCoordinator
) {
registryCoordinator = address(_slashingRegistryCoordinator);
// disable initializers so that the implementation contract cannot be initialized
_disableInitializers();
}
// storage gap for upgradeability
uint256[47] private __GAP;
}
"
},
"lib/eigenlayer-middleware/src/interfaces/ISlashingRegistryCoordinator.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {IBLSApkRegistry} from "./IBLSApkRegistry.sol";
import {IStakeRegistry} from "./IStakeRegistry.sol";
import {IIndexRegistry} from "./IIndexRegistry.sol";
import {BN254} from "../libraries/BN254.sol";
import {IAllocationManager} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IBLSApkRegistry} from "./IBLSApkRegistry.sol";
import {IStakeRegistry, IStakeRegistryTypes} from "./IStakeRegistry.sol";
import {IIndexRegistry} from "./IIndexRegistry.sol";
import {ISocketRegistry} from "./ISocketRegistry.sol";
import {BN254} from "../libraries/BN254.sol";
import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol";
interface ISlashingRegistryCoordinatorErrors {
/// @notice Thrown when array lengths in input parameters don't match.
error InputLengthMismatch();
/// @notice Thrown when an invalid registration type is provided.
error InvalidRegistrationType();
/// @notice Thrown when non-allocation manager calls restricted function.
error OnlyAllocationManager();
/// @notice Thrown when non-ejector calls restricted function.
error OnlyEjector();
/// @notice Thrown when operating on a non-existent quorum.
error QuorumDoesNotExist();
/// @notice Thrown when registering/deregistering with empty bitmap.
error BitmapEmpty();
/// @notice Thrown when registering for already registered quorums.
error AlreadyRegisteredForQuorums();
/// @notice Thrown when registering before ejection cooldown expires.
error CannotReregisterYet();
/// @notice Thrown when unregistered operator attempts restricted operation.
error NotRegistered();
/// @notice Thrown when operator attempts self-churn.
error CannotChurnSelf();
/// @notice Thrown when operator count doesn't match quorum requirements.
error QuorumOperatorCountMismatch();
/// @notice Thrown when operator has insufficient stake for churn.
error InsufficientStakeForChurn();
/// @notice Thrown when attempting to kick operator above stake threshold.
error CannotKickOperatorAboveThreshold();
/// @notice Thrown when updating to zero bitmap.
error BitmapCannotBeZero();
/// @notice Thrown when deregistering from unregistered quorum.
error NotRegisteredForQuorum();
/// @notice Thrown when churn approver salt is already used.
error ChurnApproverSaltUsed();
/// @notice Thrown when operators or quorums list is not sorted ascending.
error NotSorted();
/// @notice Thrown when maximum quorum count is reached.
error MaxQuorumsReached();
/// @notice Thrown when the provided AVS address does not match the expected one.
error InvalidAVS();
/// @notice Thrown when attempting to kick an operator that is not registered.
error OperatorNotRegistered();
/// @notice Thrown when lookAheadPeriod is greater than or equal to DEALLOCATION_DELAY.
error LookAheadPeriodTooLong();
/// @notice Thrown when the number of operators in a quorum would exceed the maximum allowed.
error MaxOperatorCountReached();
}
interface ISlashingRegistryCoordinatorTypes {
/// @notice Core data structure for tracking operator information.
/// @dev Links an operator's unique identifier with their current registration status.
/// @param operatorId Unique identifier for the operator, typically derived from their BLS public key.
/// @param status Current registration state of the operator in the system.
struct OperatorInfo {
bytes32 operatorId;
OperatorStatus status;
}
/// @notice Records historical changes to an operator's quorum registrations.
/// @dev Used for querying an operator's quorum memberships at specific block numbers.
/// @param updateBlockNumber Block number when this update occurred (inclusive).
/// @param nextUpdateBlockNumber Block number when the next update occurred (exclusive), or 0 if this is the latest update.
/// @param quorumBitmap Bitmap where each bit represents registration in a specific quorum (1 = registered, 0 = not registered).
struct QuorumBitmapUpdate {
uint32 updateBlockNumber;
uint32 nextUpdateBlockNumber;
uint192 quorumBitmap;
}
/// @notice Configuration parameters for operator management within a quorum.
/// @dev All BIPs (Basis Points) values are in relation to BIPS_DENOMINATOR (10000).
/// @param maxOperatorCount Maximum number of operators allowed in the quorum.
/// @param kickBIPsOfOperatorStake Required stake ratio (in BIPs) between new and existing operator for churn.
/// Example: 10500 means new operator needs 105% of existing operator's stake.
/// @param kickBIPsOfTotalStake Minimum stake ratio (in BIPs) of total quorum stake an operator must maintain.
/// Example: 100 means operator needs 1% of total quorum stake to avoid being churned.
struct OperatorSetParam {
uint32 maxOperatorCount;
uint16 kickBIPsOfOperatorStake;
uint16 kickBIPsOfTotalStake;
}
/// @notice Parameters for removing an operator during churn.
/// @dev Used in registerOperatorWithChurn to specify which operator to replace.
/// @param quorumNumber The quorum from which to remove the operator.
/// @param operator Address of the operator to be removed.
struct OperatorKickParam {
uint8 quorumNumber;
address operator;
}
/// @notice Represents the registration state of an operator.
/// @dev Used to track an operator's lifecycle in the system.
/// @custom:enum NEVER_REGISTERED The operator has never registered with the system.
/// @custom:enum REGISTERED The operator is currently registered and active.
/// @custom:enum DEREGISTERED The operator was previously registered but has since deregistered.
enum OperatorStatus {
NEVER_REGISTERED,
REGISTERED,
DEREGISTERED
}
/**
* @notice Enum representing the type of operator registration.
* @custom:enum NORMAL Represents a normal operator registration.
* @custom:enum CHURN Represents an operator registration during a churn event.
*/
enum RegistrationType {
NORMAL,
CHURN
}
/**
* @notice Data structure for storing the results of a registerOperator call.
* @dev Contains arrays storing per-quorum information about operator counts and stakes.
* @param numOperatorsPerQuorum For each quorum the operator registered for, stores the number of operators registered.
* @param operatorStakes For each quorum the operator registered for, stores the stake of the operator in the quorum.
* @param totalStakes For each quorum the operator registered for, stores the total stake of the quorum.
*/
struct RegisterResults {
uint32[] numOperatorsPerQuorum;
uint96[] operatorStakes;
uint96[] totalStakes;
}
}
interface ISlashingRegistryCoordinatorEvents is ISlashingRegistryCoordinatorTypes {
/**
* @notice Emitted when an operator registers for service in one or more quorums.
* @dev Emitted in _registerOperator() and _registerOperatorToOperatorSet().
* @param operator The address of the registered operator.
* @param operatorId The unique identifier of the operator (BLS public key hash).
*/
event OperatorRegistered(address indexed operator, bytes32 indexed operatorId);
/**
* @notice Emitted when an operator deregisters from service in one or more quorums.
* @dev Emitted in _deregisterOperator().
* @param operator The address of the deregistered operator.
* @param operatorId The unique identifier of the operator (BLS public key hash).
*/
event OperatorDeregistered(address indexed operator, bytes32 indexed operatorId);
/**
* @notice Emitted when a new quorum is created.
* @param quorumNumber The identifier of the quorum being created.
* @param operatorSetParams The operator set parameters for the quorum.
* @param minimumStake The minimum stake required for operators in this quorum.
* @param strategyParams The strategy parameters for stake calculation.
* @param stakeType The type of stake being tracked (TOTAL_DELEGATED or TOTAL_SLASHABLE).
* @param lookAheadPeriod The number of blocks to look ahead when calculating slashable stake (only used for TOTAL_SLASHABLE).
*/
event QuorumCreated(
uint8 indexed quorumNumber,
OperatorSetParam operatorSetParams,
uint96 minimumStake,
IStakeRegistryTypes.StrategyParams[] strategyParams,
IStakeRegistryTypes.StakeType stakeType,
uint32 lookAheadPeriod
);
/**
* @notice Emitted when a quorum's operator set parameters are updated.
* @dev Emitted in _setOperatorSetParams().
* @param quorumNumber The identifier of the quorum being updated.
* @param operatorSetParams The new operator set parameters for the quorum.
*/
event OperatorSetParamsUpdated(uint8 indexed quorumNumber, OperatorSetParam operatorSetParams);
/**
* @notice Emitted when the churn approver address is updated.
* @dev Emitted in _setChurnApprover().
* @param prevChurnApprover The previous churn approver address.
* @param newChurnApprover The new churn approver address.
*/
event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover);
/**
* @notice Emitted when the AVS address is updated.
* @param prevAVS The previous AVS address.
* @param newAVS The new AVS address.
*/
event AVSUpdated(address prevAVS, address newAVS);
/**
* @notice Emitted when the ejector address is updated.
* @dev Emitted in _setEjector().
* @param prevEjector The previous ejector address.
* @param newEjector The new ejector address.
*/
event EjectorUpdated(address prevEjector, address newEjector);
/**
* @notice Emitted when all operators in a quorum are updated simultaneously.
* @dev Emitted in updateOperatorsForQuorum().
* @param quorumNumber The identifier of the quorum being updated.
* @param blocknumber The block number at which the quorum update occurred.
*/
event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber);
/**
* @notice Emitted when an operator's socket is updated.
* @dev Emitted in updateSocket().
* @param operatorId The unique identifier of the operator (BLS public key hash).
* @param socket The new socket address for the operator (typically an IP address).
*/
event OperatorSocketUpdate(bytes32 indexed operatorId, string socket);
/**
* @notice Emitted when the ejection cooldown period is updated.
* @dev Emitted in setEjectionCooldown().
* @param prevEjectionCooldown The previous cooldown duration in seconds.
* @param newEjectionCooldown The new cooldown duration in seconds.
*/
event EjectionCooldownUpdated(uint256 prevEjectionCooldown, uint256 newEjectionCooldown);
}
interface ISlashingRegistryCoordinator is
IAVSRegistrar,
ISlashingRegistryCoordinatorErrors,
ISlashingRegistryCoordinatorEvents
{
/// IMMUTABLES & CONSTANTS
/**
* @notice EIP-712 typehash for operator churn approval signatures.
* @return The typehash constant.
*/
function OPERATOR_CHURN_APPROVAL_TYPEHASH() external view returns (bytes32);
/**
* @notice EIP-712 typehash for pubkey registration signatures.
* @return The typehash constant.
*/
function PUBKEY_REGISTRATION_TYPEHASH() external view returns (bytes32);
/**
* @notice Reference to the BLSApkRegistry contract.
* @return The BLSApkRegistry contract interface.
*/
function blsApkRegistry() external view returns (IBLSApkRegistry);
/**
* @notice Reference to the StakeRegistry contract.
* @return The StakeRegistry contract interface.
*/
function stakeRegistry() external view returns (IStakeRegistry);
/**
* @notice Reference to the IndexRegistry contract.
* @return The IndexRegistry contract interface.
*/
function indexRegistry() external view returns (IIndexRegistry);
/**
* @notice Reference to the AllocationManager contract.
* @return The AllocationManager contract interface.
* @dev This is only relevant for Slashing AVSs
*/
function allocationManager() external view returns (IAllocationManager);
/**
* @notice Reference to the SocketRegistry contract.
* @return The SocketRegistry contract interface.
*/
function socketRegistry() external view returns (ISocketRegistry);
/// STORAGE
/**
* @notice The total number of quorums that have been created.
* @return The count of quorums.
*/
function quorumCount() external view returns (uint8);
/**
* @notice Checks if a churn approver salt has been used.
* @param salt The salt to check.
* @return True if the salt has been used, false otherwise.
*/
function isChurnApproverSaltUsed(
bytes32 salt
) external view returns (bool);
/**
* @notice Gets the last block number when all operators in a quorum were updated.
* @param quorumNumber The quorum identifier.
* @return The block number of the last update.
*/
function quorumUpdateBlockNumber(
uint8 quorumNumber
) external view returns (uint256);
/**
* @notice The address authorized to approve operator churn operations.
* @return The churn approver address.
*/
function churnApprover() external view returns (address);
/**
* @notice The address authorized to forcibly eject operators.
* @return The ejector address.
*/
function ejector() external view returns (address);
/**
* @notice Gets the timestamp of an operator's last ejection.
* @param operator The operator address.
* @return The timestamp of the last ejection.
*/
function lastEjectionTimestamp(
address operator
) external view returns (uint256);
/**
* @notice The cooldown period after ejection before an operator can re-register.
* @return The cooldown duration in seconds.
*/
function ejectionCooldown() external view returns (uint256);
/// ACTIONS
/**
* @notice Updates stake weights for specified operators. If any operator is found to be below
* the minimum stake for their registered quorums, they are deregistered from those quorums.
* @param operators The operators whose stakes should be updated.
* @dev Stakes are queried from the Eigenlayer core DelegationManager contract.
* @dev WILL BE DEPRECATED IN FAVOR OF updateOperatorsForQuorum
*/
function updateOperators(
address[] memory operators
) external;
/**
* @notice For each quorum in `quorumNumbers`, updates the StakeRegistry's view of ALL its registered operators' stakes.
* Each quorum's `quorumUpdateBlockNumber` is also updated, which tracks the most recent block number when ALL registered
* operators were updated.
* @dev stakes are queried from the Eigenlayer core DelegationManager contract
* @param operatorsPerQuorum for each quorum in `quorumNumbers`, this has a corresponding list of operators to update.
* @dev Each list of operator addresses MUST be sorted in ascending order
* @dev Each list of operator addresses MUST represent the entire list of registered operators for the corresponding quorum
* @param quorumNumbers is an ordered byte array containing the quorum numbers being updated
* @dev invariant: Each list of `operatorsPerQuorum` MUST be a sorted version of `IndexRegistry.getOperatorListAtBlockNumber`
* for the corresponding quorum.
* @dev note on race condition: if an operator registers/deregisters for any quorum in `quorumNumbers` after a txn to
* this method is broadcast (but before it is executed), the method will fail
*/
function updateOperatorsForQuorum(
address[][] memory operatorsPerQuorum,
bytes calldata quorumNumbers
) external;
/**
* @notice Updates the socket of the msg.sender given they are a registered operator.
* @param socket The new socket address for the operator (typically an IP address).
* @dev Will revert if msg.sender is not a registered operator.
*/
function updateSocket(
string memory socket
) external;
/**
* @notice Forcibly removes an operator from specified quorums and sets their ejection timestamp.
* @param operator The operator address to eject.
* @param quorumNumbers The quorum numbers to eject the operator from.
* @dev Can only be called by the ejector address.
* @dev The operator cannot re-register until ejectionCooldown period has passed.
*/
function ejectOperator(address operator, bytes memory quorumNumbers) external;
/**
* @notice Creates a new quorum that tracks total delegated stake for operators.
* @param operatorSetParams Configures the quorum's max operator count and churn parameters.
* @param minimumStake Sets the minimum stake required for an operator to register or remain registered.
* @param strategyParams A list of strategies and multipliers used by the StakeRegistry to calculate
* an operator's stake weight for the quorum.
* @dev For m2 AVS this function has the same behavior as createQuorum before.
* @dev For migrated AVS that enable operator sets this will create a quorum that measures total delegated stake for operator set.
*/
function createTotalDelegatedStakeQuorum(
OperatorSetParam memory operatorSetParams,
uint96 minimumStake,
IStakeRegistryTypes.StrategyParams[] memory strategyParams
) external;
/**
* @notice Creates a new quorum that tracks slashable stake for operators.
* @param operatorSetParams Configures the quorum's max operator count and churn parameters.
* @param minimumStake Sets the minimum stake required for an operator to register or remain registered.
* @param strategyParams A list of strategies and multipliers used by the StakeRegistry to calculate
* an operator's stake weight for the quorum.
* @param lookAheadPeriod The number of blocks to look ahead when calculating slashable stake.
* @dev Can only be called when operator sets are enabled.
*/
function createSlashableStakeQuorum(
OperatorSetParam memory operatorSetParams,
uint96 minimumStake,
IStakeRegistryTypes.StrategyParams[] memory strategyParams,
uint32 lookAheadPeriod
) external;
/**
* @notice Updates the configuration parameters for an existing operator set quorum.
* @param quorumNumber The identifier of the quorum to update.
* @param operatorSetParams The new operator set parameters to apply.
* @dev Can only be called by the contract owner.
*/
function setOperatorSetParams(
uint8 quorumNumber,
OperatorSetParam memory operatorSetParams
) external;
/**
* @notice Updates the address authorized to approve operator churn operations.
* @param _churnApprover The new churn approver address.
* @dev Can only be called by the contract owner.
* @dev The churn approver is responsible for signing off on operator replacements in full quorums.
*/
function setChurnApprover(
address _churnApprover
) external;
/**
* @notice Updates the address authorized to forcibly eject operators.
* @param _ejector The new ejector address.
* @dev Can only be called by the contract owner.
* @dev The ejector can force-remove operators from quorums regardless of their stake.
*/
function setEjector(
address _ejector
) external;
/**
* @notice Updates the duration operators must wait after ejection before re-registering.
* @param _ejectionCooldown The new cooldown duration in seconds.
* @dev Can only be called by the contract owner.
*/
function setEjectionCooldown(
uint256 _ejectionCooldown
) external;
/**
* @notice Updates the avs address for this AVS (used for UAM integration in EigenLayer)
* @param _avs The new avs address
* @dev Can only be called by the contract owner
* @dev NOTE: Updating this value will break existing OperatorSets and UAM integration. This value should only be set once.
*/
function setAVS(
address _avs
) external;
/// VIEW
/**
* @notice Returns the hash of the message that operators must sign with their BLS key to register
* @param operator The operator's Ethereum address
*/
function calculatePubkeyRegistrationMessageHash(
address operator
) external view returns (bytes32);
/**
* @notice Returns the operator set parameters for a given quorum.
* @param quorumNumber The identifier of the quorum to query.
* @return The OperatorSetParam struct containing max operator count and churn thresholds.
*/
function getOperatorSetParams(
uint8 quorumNumber
) external view returns (OperatorSetParam memory);
/**
* @notice Returns the complete operator information for a given address.
* @param operator The operator address to query.
* @return An OperatorInfo struct containing the operator's ID and registration status.
*/
function getOperator(
address operator
) external view returns (OperatorInfo memory);
/**
* @notice Returns the unique identifier for a given operator address.
* @param operator The operator address to query.
* @return The operator's ID (derived from their BLS public key hash).
*/
function getOperatorId(
address operator
) external view returns (bytes32);
/**
* @notice Returns the operator address associated with a given operator ID.
* @param operatorId The unique identifier to look up.
* @return The operator's address.
* @dev Returns address(0) if the ID is not registered.
*/
function getOperatorFromId(
bytes32 operatorId
) external view returns (address);
/**
* @notice Returns the current registration status for a given operator.
* @param operator The operator address to query.
* @return The operator's status (NEVER_REGISTERED, REGISTERED, or DEREGISTERED).
*/
function getOperatorStatus(
address operator
) external view returns (OperatorStatus);
/**
* @notice Returns the indices needed to look up quorum bitmaps for operators at a specific block.
* @param blockNumber The historical block number to query.
* @param operatorIds Array of operator IDs to get indices for.
* @return Array of indices corresponding to each operator ID.
* @dev Reverts if any operator had not yet registered at the specified block.
* @dev This function is designed to find proper inputs for getQuorumBitmapAtBlockNumberByIndex.
*/
function getQuorumBitmapIndicesAtBlockNumber(
uint32 blockNumber,
bytes32[] memory operatorIds
) external view returns (uint32[] memory);
/**
* @notice Returns the quorum bitmap for an operator at a specific historical block.
* @param operatorId The operator's unique identifier.
* @param blockNumber The historical block number to query.
* @param index The index in the operator's bitmap history (from getQuorumBitmapIndicesAtBlockNumber).
* @return The quorum bitmap showing which quorums the operator was registered for.
* @dev Reverts if the index is incorrect for the specified block number.
*/
function getQuorumBitmapAtBlockNumberByIndex(
bytes32 operatorId,
uint32 blockNumber,
uint256 index
) external view returns (uint192);
/**
* @notice Returns a specific update from an operator's quorum bitmap history.
* @param operatorId The operator's unique identifier.
* @param index The index in the bitmap history to query.
* @return The QuorumBitmapUpdate struct at that index.
*/
function getQuorumBitmapUpdateByIndex(
bytes32 operatorId,
uint256 index
) external view returns (QuorumBitmapUpdate memory);
/**
* @notice Returns the current quorum bitmap for an operator.
* @param operatorId The operator's unique identifier.
* @return A bitmap where each bit represents registration in a specific quorum.
* @dev Returns 0 if the operator is not registered for any quorums.
*/
function getCurrentQuorumBitmap(
bytes32 operatorId
) external view returns (uint192);
/**
* @notice Returns the number of updates in an operator's bitmap history.
* @param operatorId The operator's unique identifier.
* @return The length of the bitmap history array.
*/
function getQuorumBitmapHistoryLength(
bytes32 operatorId
) external view returns (uint256);
/**
* @notice Calculates the digest hash that must be signed by the churn approver.
* @param registeringOperator The address of the operator attempting to register.
* @param registeringOperatorId The unique ID of the registering operator.
* @param operatorKickParams Parameters specifying which operators to replace in full quorums.
* @param salt Random value to ensure signature uniqueness.
* @param expiry Timestamp after which the signature becomes invalid.
* @return The EIP-712 typed data hash to be signed.
*/
function calculateOperatorChurnApprovalDigestHash(
address registeringOperator,
bytes32 registeringOperatorId,
OperatorKickParam[] memory operatorKickParams,
bytes32 salt,
uint256 expiry
) external view returns (bytes32);
/**
* @notice Returns the message hash that an operator must sign to register their BLS public key.
* @param operator The address of the operator registering their key.
* @return A point on the G1 curve representing the message hash.
*/
function pubkeyRegistrationMessageHash(
address operator
) external view returns (BN254.G1Point memory);
/**
* @notice Returns the avs address for this AVS (used for UAM integration in EigenLayer)
* @dev NOTE: Updating this value will break existing OperatorSets and UAM integration. This value should only be set once.
* @return The avs address
*/
function avs() external view returns (address);
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
"
},
"lib/eigenlayer-middleware/src/interfaces/IIndexRegistry.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
interface IIndexRegistryErrors {
/// @notice Thrown when a function is called by an address that is not the RegistryCoordinator.
error OnlyRegistryCoordinator();
/// @notice Thrown when attempting to query a quorum that has no history.
error QuorumDoesNotExist();
/// @notice Thrown when attempting to look up an operator that does not exist at the specified block number.
error OperatorIdDoesNotExist();
}
interface IIndexRegistryTypes {
/// @notice Represents an update to an operator's status at a specific index.
/// @param fromBlockNumber The block number from which this update takes effect.
/// @param operatorId The unique identifier of the operator.
struct OperatorUpdate {
uint32 fromBlockNumber;
bytes32 operatorId;
}
/// @notice Represents an update to the total number of operators in a quorum.
/// @param fromBlockNumber The block number from which this update takes effect.
/// @param numOperators The total number of operators after the update.
struct QuorumUpdate {
uint32 fromBlockNumber;
uint32 numOperators;
}
}
interface IIndexRegistryEvents is IIndexRegistryTypes {
/*
* @notice Emitted when an operator's index in a quorum is updated.
* @param operatorId The unique identifier of the operator.
* @param quorumNumber The identifier of the quorum.
* @param newOperatorIndex The new index assigned to the operator.
*/
event QuorumIndexUpdate(
bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex
);
}
interface IIndexRegistry is IIndexRegistryErrors, IIndexRegistryEvents {
/*
* @notice Returns the special identifier used to indicate a non-existent operator.
* @return The bytes32 constant OPERATOR_DOES_NOT_EXIST_ID.
*/
function OPERATOR_DOES_NOT_EXIST_ID() external pure returns (bytes32);
/*
* @notice Returns the address of the RegistryCoordinator contract.
* @return The address of the RegistryCoordinator.
*/
function registryCoordinator() external view returns (address);
/*
* @notice Returns the current index of an operator with ID `operatorId` in quorum `quorumNumber`.
* @dev This mapping is NOT updated when an operator is deregistered,
* so it's possible that an index retrieved from this mapping is inaccurate.
* If you're querying for an operator that might be deregistered, ALWAYS
* check this index against the latest `_operatorIndexHistory` entry.
* @param quorumNumber The identifier of the quorum.
* @param operatorId The unique identifier of the operator.
* @return The current index of the operator.
*/
function currentOperatorIndex(
uint8 quorumNumber,
bytes32 operatorId
) external view returns (uint32);
// ACTIONS
/*
* @notice Registers the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`.
* @param operatorId The unique identifier of the operator.
* @param quorumNumbers The quorum numbers to register for.
* @return An array containing a list of the number of operators (including the registering operator)
* in each of the quorums the operator is registered for.
* @dev Access restricted to the RegistryCoordinator.
* @dev Preconditions:
* 1) `quorumNumbers` has no duplicates
* 2) `quorumNumbers.length` != 0
* 3) `quorumNumbers` is ordered in ascending order
* 4) the operator is not already registered
*/
function registerOperator(
bytes32 operatorId,
bytes calldata quorumNumbers
) external returns (uint32[] memory);
/*
* @notice Deregisters the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`.
* @param operatorId The unique identifier of the operator.
* @param quorumNumbers The quorum numbers to deregister from.
* @dev Access restricted to the RegistryCoordinator.
* @dev Preconditions:
* 1) `quorumNumbers` has no duplicates
* 2) `quorumNumbers.length` != 0
* 3) `quorumNumbers` is ordered in ascending order
* 4) the operator is not already deregistered
* 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for
*/
function deregisterOperator(bytes32 operatorId, bytes calldata quorumNumbers) external;
/*
* @notice Initializes a new quorum `quorumNumber`.
* @param quorumNumber The identifier of the quorum to initialize.
*/
function initializeQuorum(
uint8 quorumNumber
) external;
// VIEW
/*
* @notice Returns the operator update at index `arrayIndex` for operator at index `operatorIndex` in quorum `quorumNumber`.
* @param quorumNumber The identifier of the quorum.
* @param operatorIndex The index of the operator.
* @param arrayIndex The index in the update history.
* @return The operator update entry.
*/
function getOperatorUpdateAtIndex(
uint8 quorumNumber,
uint32 operatorIndex,
uint32 arrayIndex
) external view returns (OperatorUpdate memory);
/*
* @notice Returns the quorum update at index `quorumIndex` for quorum `quorumNumber`.
* @param quorumNumber The identifier of the quorum.
* @param quorumIndex The index in the quorum's update history.
* @return The quorum update entry.
*/
function getQuorumUpdateAtIndex(
uint8 quorumNumber,
uint32 quorumIndex
) external view returns (QuorumUpdate memory);
/*
* @notice Returns the latest quorum update for quorum `quorumNumber`.
* @param quorumNumber The identifier of the quorum.
* @return The most recent quorum update.
*/
function getLatestQuorumUpdate(
uint8 quorumNumber
) external view returns (QuorumUpdate memory);
/*
* @notice Returns the latest operator update for operator at index `operatorIndex` in quorum `quorumNumber`.
* @param quorumNumber The identifier of the quorum.
* @param operatorIndex The index of the operator.
* @return The most recent operator update.
*/
function getLatestOperatorUpdate(
uint8 quorumNumber,
uint32 operatorIndex
) external view returns (OperatorUpdate memory);
/*
* @notice Returns the list of operators in quorum `quorumNumber` at block `blockNumber`.
* @param quorumNumber The identifier of the quorum.
* @param blockNumber The block number to query.
* @return An array of operator IDs.
*/
function getOperatorListAtBlockNumber(
uint8 quorumNumber,
uint32 blockNumber
) external view returns (bytes32[] memory);
/*
* @notice Returns the total number of operators in quorum `quorumNumber`.
* @param quorumNumber The identifier of the quorum.
* @return The total number of operators.
*/
function totalOperatorsForQuorum(
uint8 quorumNumber
) external view returns (uint32);
}
"
},
"lib/eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {BN254} from "../libraries/BN254.sol";
interface IBLSApkRegistryErrors {
/// @notice Thrown when a non-RegistryCoordinator address calls a restricted function.
error OnlyRegistryCoordinatorOwner();
/// @notice Thrown when attempting to initialize a quorum that already exists.
error QuorumAlreadyExists();
/// @notice Thrown when a quorum does not exist.
error QuorumDoesNotExist();
/// @notice Thrown when a BLS pubkey provided is zero pubkey
error ZeroPubKey();
/// @notice Thrown when an operator has already registered a BLS pubkey.
error OperatorAlreadyRegistered();
/// @notice Thrown when the operator is not registered.
error OperatorNotRegistered();
/// @notice Thrown when a BLS pubkey has already been registered for an operator.
error BLSPubkeyAlreadyRegistered();
/// @notice Thrown when either the G1 signature is wrong, or G1 and G2 private key do not match.
error InvalidBLSSignatureOrPrivateKey();
/// @notice Thrown when the quorum apk update block number is too recent.
error BlockNumberTooRecent();
/// @notice Thrown when blocknumber and index provided is not the latest apk update.
error BlockNumberNotLatest();
/// @notice Thrown when the block number is before the first update.
error BlockNumberBeforeFirstUpdate();
/// @notice Thrown when a G2 pubkey has already been set for an operator
error G2PubkeyAlreadySet();
}
interface IBLSApkRegistryTypes {
/// @notice Tracks the history of aggregate public key updates for a quorum.
/// @dev Each update contains a hash of the aggregate public key and block numbers for timing.
/// @param apkHash First 24 bytes of keccak256(apk_x0, apk_x1, apk_y0, apk_y1) representing the aggregate public key.
/// @param updateBlockNumber Block number when this update occurred (inclusive).
/// @param nextUpdateBlockNumber Block number when the next update occurred (exclusive), or 0 if this is the latest update.
struct ApkUpdate {
bytes24 apkHash;
uint32 updateBlockNumber;
uint32 nextUpdateBlockNumber;
}
/// @notice Parameters required when registering a new BLS public key.
/// @dev Contains the registration signature and both G1/G2 public key components.
/// @param pubkeyRegistrationSignature Registration message signed by operator's private key to prove ownership.
/// @param pubkeyG1 The operator's public key in G1 group format.
/// @param pubkeyG2 The operator's public key in G2 group format, must correspond to the same private key as pubkeyG1.
struct PubkeyRegistrationParams {
BN254.G1Point pubkeyRegistrationSignature;
BN254.G1Point pubkeyG1;
BN254.G2Point pubkeyG2;
}
}
interface IBLSApkRegistryEvents is IBLSApkRegistryTypes {
/*
* @notice Emitted when `operator` registers their BLS public key pair (`pubkeyG1` and `pubkeyG2`).
* @param operator The address of the operator registering the keys.
* @param pubkeyG1 The operator's G1 public key.
* @param pubkeyG2 The operator's G2 public key.
*/
event NewPubkeyRegistration(
address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2
);
/*
* @notice Emitted when `operator`'s pubkey is registered for `quorumNumbers`.
* @param operator The address of the operator being registered.
* @param operatorId The unique identifier for this operator (pubkey hash).
* @param quorumNumbers The quorum numbers the operator is being registered for.
*/
event OperatorAddedToQuorums(address operator, bytes32 operatorId, bytes quorumNumbers);
/*
* @notice Emitted when `operator`'s pubkey is deregistered from `quorumNumbers`.
* @param operator The address of the operator being deregistered.
* @param operatorId The unique identifier for this operator (pubkey hash).
* @param quorumNumbers The quorum numbers the operator is being deregistered from.
*/
event OperatorRemovedFromQuorums(address operator, bytes32 operatorId, bytes quorumNumbers);
/// @notice Emitted when a G2 public key is registered for an operator
event NewG2PubkeyRegistration(address indexed operator, BN254.G2Point pubkeyG2);
}
interface IBLSApkRegistry is IBLSApkRegistryErrors, IBLSApkRegistryEvents {
/* STORAGE */
/*
* @notice Returns the address of the registry coordinator contract.
* @return The address of the registry coordinator.
* @dev This value is immutable and set during contract construction.
*/
function registryCoordinator() external view returns (address);
/*
* @notice Maps `operator` to their BLS public key hash (`operatorId`).
* @param operator The address of the operator.
* @return operatorId The hash of the operator's BLS public key.
*/
function operatorToPubkeyHash(
address operator
) external view returns (bytes32 operatorId);
/*
* @notice Maps `pubkeyHash` to their corresponding `operator` address.
* @param pubkeyHash The hash of a BLS public key.
* @return operator The address of the operator who registered this public key.
*/
function pubkeyHashToOperator(
bytes32 pubkeyHash
) external view returns (address operator);
/*
* @notice Maps `operator` to their BLS public key in G1.
* @dev Returns a non-encoded BN254.G1Point.
* @param operator The address of the operator.
* @return The operator's BLS public key in G1.
*/
function operatorToPubkey(
address operator
) external view returns (uint256, uint256);
/*
* @notice Maps `operator` to their BLS public key in G2.
* @param operator The address of the operator.
* @return The operator's BLS public key in G2.
*/
function getOperatorPubkeyG2(
address operator
) external view returns (BN254.G2Point memory);
/*
* @notice Stores the history of aggregate public key updates for `quorumNumber` at `index`.
* @dev Returns a non-encoded IBLSApkRegistryTypes.ApkUpdate.
* @param quorumNumber The identifier of the quorum.
* @param index The index in the history array.
* @return The APK update entry at the specified index for the given quorum.
* @dev Each entry contains the APK hash, update block number, and next update block number.
*/
function apkHistory(
uint8 quorumNumber,
uint256 index
) external view returns (bytes24, uint32, uint32);
/*
* @notice Maps `quorumNumber` to their current aggregate public key.
* @dev Returns a non-encoded BN254.G1Point.
* @param quorumNumber The identifier of the quorum.
* @return The current APK as a G1 point.
*/
function currentApk(
uint8 quorumNumber
) external view returns (uint256, uint256);
/* ACTIONS */
/*
* @notice Registers `operator`'s pubkey for `quorumNumbers`.
* @param operator The address of the operator to register.
* @param quorumNumbers The quorum numbers to register for, where each byte is an
Submitted on: 2025-10-14 17:34:39
Comments
Log in to comment.
No comments yet.