### Install Project Dependencies Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/CONTRIBUTING.md Installs project dependencies using npm, initializes Husky for Git hooks, and installs Solidity dependencies using Forge. Ensure Node.js and Foundry are installed. ```bash npm install npx husky install forge install ``` -------------------------------- ### Clone EigenLayer Middleware Repository Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/CONTRIBUTING.md This command clones the EigenLayer Middleware repository from GitHub. Ensure you have Git installed and configured with SSH keys for access. ```bash git clone git@github.com:Layr-Labs/eigenlayer-middleware.git ``` -------------------------------- ### Initialize AVSRegistrar (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Initializes the AVSRegistrar contract, setting up the AVS with administrative control and metadata. This process involves updating AVS metadata in the AllocationManager, designating itself as the AVS registrar, and initiating an admin transfer via the PermissionController. It is intended for use during contract deployment or setup. ```solidity /** * @notice Initialize the AVS with metadata and admin * @param admin The address that will control the AVS * @param metadataURI The metadata URI for the AVS */ function initialize(address admin, string memory metadataURI) public initializer; ``` -------------------------------- ### Solidity State History Structure Example Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/README.md This Solidity struct defines a common pattern for tracking state histories over time. It includes the value itself and block numbers indicating when the value became valid and when it ceases to be valid. This is useful for off-chain code to query historical states. ```solidity struct ValueUpdate { Value value; uint32 updateBlockNumber; // when the value started being valid uint32 nextUpdateBlockNumber; // when the value stopped being valid (or 0, if the value is still valid) } ``` -------------------------------- ### Get All Allowed Operators (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Retrieves an array of all operator addresses that are currently on the allowlist for a specified operator set. This is a view function and does not alter contract state. It returns a dynamic array of addresses. ```solidity /** * @notice Get all operators on the allowlist for a specific operator set * @param operatorSet The operator set to query * @return Array of allowed operator addresses */ function getAllowedOperators(OperatorSet memory operatorSet) external view returns (address[] memory); ``` -------------------------------- ### Running Forge Tests with Verbose Logging Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/test/integration/README.md This command executes Forge tests with a high level of verbosity (-vvvv) to enable detailed logging. This is crucial for debugging, as it allows inspection of the test execution flow and assertion failures. The example shows how to target a specific test for re-running. ```shell forge test --match-test testFuzz_churnAll_deregisterAll_reregisterAll -vvvv ``` -------------------------------- ### Get Operator State by Quorum Numbers (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/OperatorStateRetriever.md Fetches comprehensive information for operators registered in specified quorums at a given block number. It queries the IndexRegistry, BLSApkRegistry, and StakeRegistry to compile a detailed list of operators, their addresses, IDs, and stakes for each requested quorum. ```solidity function getOperatorState( ISlashingRegistryCoordinator registryCoordinator, bytes memory quorumNumbers, uint32 blockNumber ) public view returns (Operator[][] memory) ``` -------------------------------- ### Interpreting Foundry Test Failure Logs Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/test/integration/README.md This log output demonstrates a typical Foundry test failure scenario, including the final assertion failure and a detailed trace of execution logs. The logs, which include calls to `User` methods and internal functions, help identify the point of failure, even when Foundry continues execution after an assertion. The example highlights how to trace back to the first `Error` message to find the root cause. ```log alex-pc$ forge test --match-test testFuzz_churnAll_deregisterAll_reregisterAll -vvvv Running 1 test for test/integration/tests/Full_Register_Deregister.t.sol:Integration_Full_Register_Deregister [FAIL. Reason: revert: Hello; counterexample: calldata=0x2deac5e50000000000000000000000000000000000000000000000000000000000000000 args=[0]] testFuzz_churnAll_deregisterAll_reregisterAll(uint24) (runs: 0, μ: 0, ~: 0) Logs: _randUser: Created user: Operator2 _dealRandTokens: dealing assets to: Operator2 Operator2.registerAsOperator (core) Operator2.depositIntoEigenLayer (core) _getChurnTargets: incoming operator: Operator2 _getChurnTargets: churnQuorums: [0] _getChurnTargets: standardQuorums: [] _getChurnTargets: making room by removing operators from quorums: [] Error: _getChurnTargets: non-full quorum cannot be churned Error: Assertion Failed _getChurnTargets: selected churn target for quorum 0: Operator1_Alt _dealMaxTokens: dealing assets to: Operator2 Operator2.depositIntoEigenLayer (core) - check_Never_Registered(Operator2) Operator2.registerOperatorWithChurn - standardQuorums: [] - churnQuorums: [0] - churnTargets: [Operator1_Alt] - check_Churned_State(Operator2) Error: operator pubkey should have been added and churned operator pubkeys should have been removed from apks Error: a == b not satisfied [uint] Left: 2582841356496569783701107773744347400602274420730358719910718097198309395114 Right: 10822086612829857808151829430341754119262204537621155540191069406696407943166 Error: operator pubkey should have been added and churned operator pubkeys should have been removed from apks Error: a == b not satisfied [uint] Left: 13247024643142095460619063135556783356345434798583216080148658194941536279140 Right: 13770989844474892507527416045106729498410917265852017889139336639541758415479 Error: failed to add operator weight and remove churned weight from each quorum Error: a == b not satisfied [uint] Left: 1021270404 Right: 1013316117 ``` -------------------------------- ### Initialize Allowlist in Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md This Solidity function initializes the allowlist mechanism by setting an administrator. The designated admin will have ownership and control over the allowlist, including managing operator additions and removals. This function can only be called once. ```solidity /** * @notice Initialize the allowlist with an admin * @param admin The address that can manage the allowlist */ function initialize(address admin) public override initializer; ``` -------------------------------- ### _getOperatorWeights Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/OperatorTableCalculator.md Abstract function to get operator weights for a given operator set. Must be implemented by derived contracts. ```APIDOC ## `_getOperatorWeights` ### Description Abstract function to get the operator weights for a given operator set. This function must be implemented by derived contracts to define specific weight calculation logic. AVSs must ensure that all operators have an identical weights structure and length types when implementing this function, otherwise verification issues may arise. ### Method `internal view virtual` ### Endpoint N/A (Solidity function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **operatorSet** (OperatorSet) - Required - The operatorSet to get the weights for. ### Request Example ```json { "operatorSet": { ... } } ``` ### Response #### Success Response (200) - **operators** (address[]) - The addresses of the operators in the operatorSet. - **weights** (uint256[][]) - The weights for each operator. This is a 2D array where the first index is the operator and the second index is the type of weight. #### Response Example ```json { "operators": ["0x..."], "weights": [[100, 50]] } ``` ``` -------------------------------- ### AVSRegistrarWithAllowlist Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Gates registration by maintaining per-operatorSet allowlists. Checks allowlist in the `_beforeRegisterOperator` hook. ```APIDOC ## AVSRegistrarWithAllowlist Gates registration by maintaining per-operatorSet allowlists. The `AVSRegistrarWithAllowlist`: - Inherits from `Allowlist` module - Checks allowlist in the `_beforeRegisterOperator` hook - Gates registration on allowlist membership. Deregistration can be completed regardless of allowlist membership ### Initialization #### `initialize` - **Description**: Initialize the allowlist with an admin. - **Method**: `POST` (Public initializer function in Solidity) - **Endpoint**: Not applicable (Solidity function call) - **Parameters**: - **`admin`** (address) - Required - The address that can manage the allowlist. - **Note**: The admin set in this function is the owner of the contract, which gates the below `Allowlist` methods. ### Key Methods (from Allowlist) #### `addOperatorToAllowlist` - **Description**: Add an operator to the allowlist for a specific operator set. - **Method**: `POST` (External function in Solidity) - **Endpoint**: Not applicable (Solidity function call) - **Parameters**: - **`operatorSet`** (OperatorSet) - Required - The operator set to update. - **`operator`** (address) - Required - The operator to add. - **Requirements**: - Caller MUST be the contract owner. - Operator MUST NOT already be in the allowlist for this operator set. - **Effects**: - Adds operator to the allowlist for the specified operator set. - Emits `OperatorAddedToAllowlist` event. ``` -------------------------------- ### Get AVS Directory Address (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/ServiceManagerBase.md Returns the address of the EigenLayer AVSDirectory contract. This function is intended for off-chain use to interact with the directory service. ```solidity function avsDirectory() external view override returns (address) ``` -------------------------------- ### Initialize Quorum Configuration (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/registries/BLSApkRegistry.md The `initializeQuorum` function sets up a new quorum, which is callable only by the `RegistryCoordinator`. It initializes the quorum by adding an `ApkUpdate` with a zeroed `apkHash` to the `apkHistory`. This action validates the existence of a quorum and is typically performed when a new quorum is created by the `RegistryCoordinatorOwner`. ```solidity function initializeQuorum( uint8 quorumNumber ) public virtual onlyRegistryCoordinator ``` -------------------------------- ### Configure Fuzzing with _configRand Method (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/test/integration/README.md This Solidity code snippet demonstrates how to use the `_configRand` method to configure fuzzing parameters. It accepts flags for user types and quorum configurations, affecting the generation of users and quorums in tests. Dependencies include the `User` and `User_AltMethods` contracts, and constants like `DEFAULT`, `ALT_METHODS`, `ONE`, `TWO`, `MANY`, `NO_MINIMUM`, `HAS_MINIMUM`, `EMPTY`, `SOME_FILL`, and `FULL`. ```solidity function testFuzz_someFlow(uint24 _random) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, _quorumConfig: QuorumConfig({ numQuorums: ONE | TWO | MANY, numStrategies: ONE | TWO | MANY, minimumStake: NO_MINIMUM | HAS_MINIMUM, fillTypes: EMPTY | SOME_FILL | FULL }) }); } ``` -------------------------------- ### Get Operator Infos (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/OperatorTableCalculator.md Retrieves an array of BN254OperatorInfo structs for all operators within a given operatorSet who have registered BN254 keys. This is a view function and does not modify state. ```solidity /** * @notice Get the operatorInfos for a given operatorSet * @param operatorSet the operatorSet to get the operatorInfos for * @return operatorInfos the operatorInfos for the given operatorSet */ function getOperatorInfos( OperatorSet calldata operatorSet ) external view returns (BN254OperatorInfo[] memory operatorInfos); ``` -------------------------------- ### Get Operator Socket URL in Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md This Solidity function retrieves the socket URL associated with a given operator address. It is a view function, meaning it does not modify the blockchain state. If no socket URL is set for the operator, it returns an empty string. ```solidity /** * @notice Get the socket URL for an operator * @param operator The operator address * @return The operator's socket URL */ function getOperatorSocket( address operator ) external view returns (string memory); ``` -------------------------------- ### Implement Instant Slashing for Operator Misbehavior (Solidity) Source: https://context7.com/layr-labs/eigenlayer-middleware/llms.txt Demonstrates how to slash an operator for submitting an invalid fraud proof using the InstantSlasher contract. This involves verifying the proof, calculating the slashable amount based on the operator's stake, and executing the slash transaction. Dependencies include InstantSlasher, ServiceManagerBase, and various EigenLayer registry contracts. It takes operator address, quorum number, and fraud proof as input, and outputs an event indicating the operator was slashed. ```solidity // SPDX-License-Identifier: MIT\npragma solidity ^0.8.27;\n\nimport "./src/slashers/InstantSlasher.sol";\nimport "./src/ServiceManagerBase.sol";\n\ncontract SlashingExample is ServiceManagerBase {\n InstantSlasher public slasher;\n\n function slashOperatorForInvalidProof(\n address operator,\n uint8 quorumNumber,\n bytes memory fraudProof\n ) external {\n // Verify fraud proof (AVS-specific logic)\n require(verifyFraudProof(operator, fraudProof), "Invalid fraud proof");\n\n // Get operator's allocated stake for this AVS\n bytes32 operatorId = registryCoordinator.getOperatorId(operator);\n uint96 operatorStake = stakeRegistry.getCurrentStake(operatorId, quorumNumber);\n\n // Calculate slash amount (e.g., 10% of stake)\n uint256 slashAmount = (operatorStake * 10) / 100;\n\n // Prepare slash request\n IInstantSlasherTypes.SlashRequest memory slashRequest = IInstantSlasherTypes.SlashRequest({\n operator: operator,\n operatorSetId: uint32(quorumNumber),\n strategies: getStrategiesForOperator(operator, quorumNumber),\n wadToSlash: uint256(slashAmount),\n description: "Fraud proof violation - invalid attestation" });\n\n // Execute instant slash - funds immediately slashed and sent to recipient\n slasher.slashOperator(\n address(this), // AVS as slash recipient\n slashRequest\n );\n\n // Optionally eject operator from quorum\n registryCoordinator.ejectOperator(operator, bytes1(quorumNumber));\n\n emit OperatorSlashed(operator, quorumNumber, slashAmount);\n }\n\n function verifyFraudProof(address operator, bytes memory proof) internal view returns (bool) {\n // AVS-specific fraud proof verification\n // Examples:\n // - Double-signing detection\n // - Invalid state transition proof\n // - Incorrect data availability attestation\n return true; // Simplified\n }\n\n function getStrategiesForOperator(address operator, uint8 quorumNumber)\n internal\n view\n returns (IStrategy[] memory)\n {\n IStakeRegistryTypes.StrategyParams[] memory strategyParams =\n stakeRegistry.strategyParamsForQuorum(quorumNumber);\n\n IStrategy[] memory strategies = new IStrategy[](strategyParams.length);\n for (uint256 i = 0; i < strategyParams.length; i++) {\n strategies[i] = strategyParams[i].strategy;\n }\n return strategies;\n }\n\n event OperatorSlashed(address indexed operator, uint8 quorumNumber, uint256 amount);\n} ``` -------------------------------- ### Get Restakeable Strategies (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/ServiceManagerBase.md Retrieves a list of strategy addresses supported by the AVS for restaking. This function is intended for off-chain use by the rewards calculation system and returns an array of strategy addresses across all quorums. ```solidity function getRestakeableStrategies() external view virtual returns (address[] memory) ``` -------------------------------- ### Build and Test EigenLayer Middleware with Foundry Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/README.md Instructions for building the EigenLayer Middleware project and running tests using Foundry. This involves updating Foundry and then executing build and test commands. Foundry is a required tool for this process. ```shell foundryup forge build forge test ``` -------------------------------- ### AVSRegistrarAsIdentifier Initialization Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Initializes the AVSRegistrar contract, setting up AVS metadata and administrative control. ```APIDOC ## POST /initialize ### Description Initializes the AVSRegistrar contract with administrative credentials and metadata. This process updates AVS metadata, designates the registrar, and initiates an admin transfer. ### Method POST ### Endpoint /initialize ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **admin** (address) - Required - The address that will control the AVS. - **metadataURI** (string) - Required - The metadata URI for the AVS. ### Request Example ```json { "admin": "0x123abc...", "metadataURI": "https://example.com/avs/metadata" } ``` ### Response #### Success Response (200) This function initiates a multi-step initialization process and does not return data directly. It is marked as `initializer` indicating it can only be called once. #### Response Example (No direct response body for this initializer function, but events related to metadata update and admin transfer may be emitted.) ``` -------------------------------- ### Initialize Delegated Stake Quorum with Strategies (Solidity) Source: https://context7.com/layr-labs/eigenlayer-middleware/llms.txt Initializes a new quorum for tracking delegated stake. This involves defining an array of strategies, each with a specific weight multiplier, and setting a minimum stake requirement. Delegated stake is determined by the total amount delegated to an operator in the DelegationManager. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import "./src/StakeRegistry.sol"; import "./src/interfaces/IStakeRegistry.sol"; contract QuorumInitializationExample { StakeRegistry public stakeRegistry; function initializeDelegatedStakeQuorum() external { // Configure strategies and their weights for the quorum IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](3); // Strategy 1: stETH with 1x multiplier strategyParams[0] = IStakeRegistryTypes.StrategyParams({ strategy: IStrategy(0x93c4b944D05dfe6df7645A86cd2206016c51564D), // stETH strategy multiplier: 1e18 // 1x weight }); // Strategy 2: rETH with 1.5x multiplier (higher weight) strategyParams[1] = IStakeRegistryTypes.StrategyParams({ strategy: IStrategy(0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2), // rETH strategy multiplier: 1.5e18 // 1.5x weight }); // Strategy 3: cbETH with 0.8x multiplier strategyParams[2] = IStakeRegistryTypes.StrategyParams({ strategy: IStrategy(0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc), // cbETH strategy multiplier: 0.8e18 // 0.8x weight }); uint8 quorumNumber = 0; // Initialize quorum 0 uint96 minimumStake = 1 ether; // Minimum 1 ETH equivalent to register // Initialize delegated stake quorum // Delegated stake = total amount delegated to operator in DelegationManager stakeRegistry.initializeDelegatedStakeQuorum( quorumNumber, minimumStake, strategyParams ); // Quorum 0 is now configured: // - Tracks delegated stake from 3 strategies // - Requires minimum 1 ETH to register // - Applies multipliers: stETH (1x), rETH (1.5x), cbETH (0.8x) } function initializeSlashableStakeQuorum() external { // Configure strategies for slashable stake tracking IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](2); strategyParams[0] = IStakeRegistryTypes.StrategyParams({ strategy: IStrategy(0x93c4b944D05dfe6df7645A86cd2206016c51564D), multiplier: 1e18 }); strategyParams[1] = IStakeRegistryTypes.StrategyParams({ strategy: IStrategy(0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2), multiplier: 1e18 }); uint8 quorumNumber = 1; uint96 minimumStake = 10 ether; // Initialize slashable stake quorum // Slashable stake = amount allocated to AVS through AllocationManager // Operators must allocate before registering stakeRegistry.initializeSlashableStakeQuorum( quorumNumber, minimumStake, strategyParams ); // Quorum 1 now tracks slashable stake: // - Only counts stake explicitly allocated to this AVS // - Higher minimum requirement (10 ETH) // - Stake is subject to slashing conditions } } ``` -------------------------------- ### Get Operator Restaked Strategies (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/ServiceManagerBase.md Retrieves a list of strategy addresses that a specific operator has potentially restaked with the AVS. This function is intended for off-chain use by the rewards calculation system and returns an array of strategy addresses for the operator across all registered quorums. ```solidity function getOperatorRestakedStrategies( address operator ) external view virtual returns (address[] memory) ``` -------------------------------- ### Get Operator State by Operator ID - Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/BLSSignatureChecker.md Retrieves an operator's registered quorums and associated operator details at a specific block number. It traverses history across RegistryCoordinator, IndexRegistry, and StakeRegistry. Returns a bitmap of quorums and a list of operators per quorum, including their stake. ```solidity function getOperatorState( IRegistryCoordinator registryCoordinator, bytes32 operatorId, uint32 blockNumber ) external view returns (uint256, Operator[][] memory) struct Operator { bytes32 operatorId; uint96 stake; } ``` -------------------------------- ### Initialize Slashable Stake Quorum - Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/registries/StakeRegistry.md Initializes a new slashable stake quorum, configuring minimum stake, strategy parameters, and a look-ahead period for slashable stake calculations. This function is restricted to the RegistryCoordinator and requires a non-initialized quorum number. Effects include adding strategies, setting minimum stake, slashable look-ahead, and pushing an initial StakeUpdate. ```solidity function initializeSlashableStakeQuorum( uint8 quorumNumber, uint96 minimumStake, uint32 lookAheadPeriod, StrategyParams[] memory _strategyParams ) public virtual onlyRegistryCoordinator struct StrategyParams { IStrategy strategy; uint96 multiplier; } ``` -------------------------------- ### Get Operator State by Quorum Numbers - Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/BLSSignatureChecker.md Retrieves the set of operators registered for specified quorums at a given block number. This function also traverses history in the RegistryCoordinator, IndexRegistry, and StakeRegistry. It returns a nested array of operators, where each inner array corresponds to a quorum and lists the registered operators with their stake. ```solidity function getOperatorState( IRegistryCoordinator registryCoordinator, bytes memory quorumNumbers, uint32 blockNumber ) public view returns(Operator[][] memory) ``` -------------------------------- ### Initialization API Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/EjectionManager.md API for initializing the EjectionManager contract. ```APIDOC ## POST /api/ejection/initialize ### Description Initializes the EjectionManager contract with the owner, initial ejectors, and quorum ejection parameters. ### Method POST ### Endpoint /api/ejection/initialize ### Parameters #### Request Body - **_owner** (address) - Required - The address of the contract owner. - **_ejectors** (address[]) - Required - An array of initial ejector addresses. - **_quorumEjectionParams** (object[]) - Required - An array of quorum ejection parameters. - **ejectableStakePercent** (uint256) - The percentage of stake that can be ejected. - **rateLimitWindow** (uint256) - The time window for rate limiting in seconds. ### Request Example ```json { "_owner": "0x1234567890abcdef1234567890abcdef12345678", "_ejectors": ["0xabcdef1234567890abcdef1234567890abcdef12345678"], "_quorumEjectionParams": [ { "ejectableStakePercent": 1000, "rateLimitWindow": 3600 } ] } ``` ### Response #### Success Response (200) - **message** (string) - Indicates successful initialization of the EjectionManager contract. #### Response Example ```json { "message": "EjectionManager contract initialized successfully." } ``` ### Requirements * Can only be called once due to the `initializer` modifier. ``` -------------------------------- ### Initialize Delegated Stake Quorum - Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/registries/StakeRegistry.md Initializes a new delegated stake quorum by setting a minimum stake and associated strategy parameters. It is callable only by the RegistryCoordinator and requires the quorum number to not already be initialized. Effects include adding strategies, setting minimum stake, and pushing an initial StakeUpdate. ```solidity function initializeDelegatedStakeQuorum( uint8 quorumNumber, uint96 minimumStake, StrategyParams[] memory _strategyParams ) public virtual onlyRegistryCoordinator struct StrategyParams { IStrategy strategy; uint96 multiplier; } ``` -------------------------------- ### Get Check Signatures Indices - Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/BLSSignatureChecker.md Computes indices into historical state for various registries to facilitate efficient offchain signature verification. It traverses histories in RegistryCoordinator, IndexRegistry, StakeRegistry, and BLSApkRegistry. The function returns indices related to non-signer quorums, quorum APKs, total stakes, and non-signer stakes within specific quorums. ```solidity function getCheckSignaturesIndices( IRegistryCoordinator registryCoordinator, uint32 referenceBlockNumber, bytes calldata quorumNumbers, bytes32[] calldata nonSignerOperatorIds ) external view returns (CheckSignaturesIndices memory) struct CheckSignaturesIndices { uint32[] nonSignerQuorumBitmapIndices; uint32[] quorumApkIndices; uint32[] totalStakeIndices; uint32[][] nonSignerStakeIndices; // nonSignerStakeIndices[quorumNumberIndex][nonSignerIndex] } ``` -------------------------------- ### List Git Tags Sorted by Date Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/CHANGELOG/CHANGELOG-template.md This command lists all Git tags in the repository, sorted by their creation date in descending order. It is used to identify the most recent release tag, which is necessary for generating the changelog. ```bash git tag --sort=-creatordate ``` -------------------------------- ### Get Operator State by Operator ID (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/OperatorStateRetriever.md Retrieves an operator's registered quorums and their state at a specific block number. It fetches the quorum bitmap, converts it to an array of quorum numbers, and then lists all operators within those quorums, including their addresses, IDs, and stakes. This method is useful for AVS operators preparing for new tasks. ```solidity function getOperatorState( ISlashingRegistryCoordinator registryCoordinator, bytes32 operatorId, uint32 blockNumber ) external view returns (uint256, Operator[][] memory) struct Operator { address operator; bytes32 operatorId; uint96 stake; } ``` -------------------------------- ### Calculate Individual Operator Kick Threshold Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/SlashingRegistryCoordinator.md A pure internal function to calculate the minimum stake percentage (in basis points) by which a new operator's stake must exceed an existing operator's stake to qualify for churn. It takes the operator's current stake and set parameters as input. ```solidity function _individualKickThreshold( uint96 operatorStake, OperatorSetParam memory setParams ) internal pure ``` -------------------------------- ### Set AVS Address in SlashingRegistryCoordinator Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/SlashingRegistryCoordinator.md Sets the AVS address within the SlashingRegistryCoordinator contract. This address is crucial for UAM integration. Note that updating this value after initial setup will disrupt existing operator sets, so it should ideally be set only once. The expected address is that of the ServiceManager contract. This function requires the caller to be the contract owner and results in the 'avs' address being set. ```solidity function setAVS( address _avs ) external { // Implementation details... } ``` -------------------------------- ### Create Slashable Operator Set in Solidity Source: https://context7.com/layr-labs/eigenlayer-middleware/llms.txt This Solidity function demonstrates how to create a new slashable operator set using the AllocationManager and SlashingRegistryCoordinator. It configures parameters such as maximum operator count, kick thresholds, minimum stake, and associated strategies. The function initializes a quorum with these settings. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import "./src/SlashingRegistryCoordinator.sol"; import "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; contract OperatorSetManagementExample { SlashingRegistryCoordinator public coordinator; IAllocationManager public allocationManager; function createSlashableOperatorSet() external { uint8 quorumNumber = 2; // Create quorum 2 as operator set // Configure operator set parameters ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 100, kickBIPsOfOperatorStake: 1500, // 15% - kicked operator must have <15% of incoming operator's stake kickBIPsOfTotalStake: 100 // 1% - kicked operator must have <1% of total stake }); // Configure stake requirements uint96 minimumStake = 32 ether; // Minimum 32 ETH IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = IStakeRegistryTypes.StrategyParams({ strategy: IStrategy(0x93c4b944D05dfe6df7645A86cd2206016c51564D), multiplier: 1e18 }); // Create operator set in AllocationManager and initialize quorum coordinator.createSlashableOperatorSet({ quorumNumber: quorumNumber, operatorSetParams: operatorSetParams, minimumStake: minimumStake, strategyParams: strategyParams }); // Operator set created with ID = quorumNumber // Operators can now allocate stake and register } function forceEjectOperator(address operator, uint8 quorumNumber) external { // Force eject operator (e.g., due to inactivity or violation) // Only callable by authorized address (e.g., AVS owner) // Eject removes operator immediately from quorum // Stake enters deallocation period coordinator.ejectOperator( operator, bytes1(quorumNumber) ); emit OperatorEjected(operator, quorumNumber); } function updateOperatorSetParams(uint8 quorumNumber) external { // Update operator set parameters after creation ISlashingRegistryCoordinatorTypes.OperatorSetParam memory newParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 200, // Increase capacity kickBIPsOfOperatorStake: 2000, // 20% kickBIPsOfTotalStake: 150 // 1.5% }); coordinator.setOperatorSetParams(quorumNumber, newParams); emit OperatorSetParamsUpdated(quorumNumber); } event OperatorEjected(address indexed operator, uint8 quorumNumber); event OperatorSetParamsUpdated(uint8 indexed quorumNumber); } ``` -------------------------------- ### Get Operator Weights (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/OperatorTableCalculator.md An abstract function that must be implemented by derived contracts to define the specific weight calculation logic for an operatorSet. It returns the addresses of operators and a 2D array of their weights across different stake types. Implementations must ensure all operators have an identical weights structure and length to avoid silent verification failures. ```solidity /** * @notice Abstract function to get the operator weights for a given operatorSet * @param operatorSet The operatorSet to get the weights for * @return operators The addresses of the operators in the operatorSet * @return weights The weights for each operator in the operatorSet, this is a 2D array where the first index is the operator * and the second index is the type of weight * @dev Each single `weights` array is as a list of arbitrary stake types. For example, * it can be [slashable_stake, delegated_stake, strategy_i_stake, ...]. Each stake type is an index in the array * @dev Must be implemented by derived contracts to define specific weight calculation logic * @dev The certificate verification assumes the composition weights array for each operator is the same. * If the length of the array is different or the stake types are different, then verification issues can arise, including * verification failing silently for multiple operators with different weights structures */ function _getOperatorWeights( OperatorSet calldata operatorSet ) internal view virtual returns (address[] memory operators, uint256[][] memory weights); ``` -------------------------------- ### Get Ejectable Stake Amount for Quorum with Solidity Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/EjectionManager.md Calculates the amount of stake that can currently be ejected from a quorum. This function considers the quorum's ejection parameters and recent ejection history to determine the remaining ejectable stake within the current rate limit window. It returns the calculated amount, which is the difference between the total allowed ejectable stake and the stake already ejected. ```solidity function amountEjectableForQuorum( uint8 quorumNumber ) public view returns (uint256) ``` -------------------------------- ### Define Operator Set Parameters Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/SlashingRegistryCoordinator.md Defines the parameters for an operator set, including the maximum number of operators, and kick parameters based on operator and total stake. ```solidity struct OperatorSetParam { uint32 maxOperatorCount; uint16 kickBIPsOfOperatorStake; uint16 kickBIPsOfTotalStake; } ``` -------------------------------- ### Operator Key Rotation Sequence Diagram Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Visualizes the sequence of operations for an operator to rotate their key, involving the Operator, AllocationManager, and KeyRegistrar. It highlights the deregistration and re-registration steps with a mandatory waiting period if the operator was previously allocated. ```mermaid sequenceDiagram participant OP as Operator participant AM as AllocationManager participant KR as KeyRegistrar OP->>AM: Tx1: deregisterFromOperatorSets Note over OP: Wait 14 days
(if previously allocated) OP->>KR: Tx2: deregisterKey OP->>AM: Tx3: register new key to operatorSet ``` -------------------------------- ### Verify and Register G2 Public Key for Operator (Solidity) Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/registries/BLSApkRegistry.md The `verifyAndRegisterG2PubkeyForOperator` function securely registers a G2 public key for an operator that already possesses a G1 key. It verifies that the BLS key pair originates from the same secret key, ensuring data integrity. This method is callable only by the `RegistryCoordinatorOwner` and stores the G2 key in `operatorToPubkeyG2`. ```solidity function verifyAndRegisterG2PubkeyForOperator( address operator, BN254.G2Point calldata pubkeyG2 ) external onlyRegistryCoordinatorOwner ``` -------------------------------- ### AVSRegistrarWithSocket Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Extends the base registrar to store a socket URL for each operator. Allows operators to update their socket URLs post-registration. ```APIDOC ## AVSRegistrarWithSocket Extends the base registrar to store a socket URL for each operator. The `AVSRegistrarWithSocket`: - Inherits from `SocketRegistry` module - Stores socket URLs in the `_afterRegisterOperator` hook - Allows operators to update their socket URLs post-registration **Note:** Sockets are global for the AVS and cannot be set on a per-operatorSet basis. The socket is updated on every registration call, regardless if the operator has already registered to a different operatorSet. Sockets are *not* cleared upon deregistration. ### Key Methods (from SocketRegistry) #### `getOperatorSocket` - **Description**: Get the socket URL for an operator. - **Method**: `GET` (View function in Solidity) - **Endpoint**: Not applicable (Solidity function call) - **Parameters**: - **`operator`** (address) - Required - The operator address. - **Response**: - **`operator's socket URL`** (string) - The operator's socket URL (empty string if not set). #### `updateSocket` - **Description**: Updates the socket for an operator. - **Method**: `POST` (External function in Solidity) - **Endpoint**: Not applicable (Solidity function call) - **Parameters**: - **`operator`** (address) - Required - The operator to set the socket for. - **`socket`** (string) - Required - The socket to set for the operator. - **Requirements**: - Caller MUST be authorized, either as the operator themselves or an admin/appointee. - **Effects**: - Updates the stored socket URL for the operator. - Emits `OperatorSocketSet` event. ``` -------------------------------- ### Operator Allowlist Management Source: https://github.com/layr-labs/eigenlayer-middleware/blob/dev/docs/middlewareV2/AVSRegistrar.md Manage the allowlist of operators for specific operator sets. ```APIDOC ## POST /removeOperatorFromAllowlist ### Description Removes an operator from the allowlist for a specific operator set. This action can only be performed by the contract owner and requires the operator to be currently on the allowlist. ### Method POST ### Endpoint /removeOperatorFromAllowlist ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **operatorSet** (OperatorSet memory) - Required - The operator set to update. - **operator** (address) - Required - The operator address to remove from the allowlist. ### Request Example ```json { "operatorSet": { "operatorSetID": "0x123...", "maxOperators": 100, "minOperators": 10 }, "operator": "0xabc..." } ``` ### Response #### Success Response (200) This function does not return data but emits an `OperatorRemovedFromAllowlist` event upon successful execution. #### Response Example ```json { "event": "OperatorRemovedFromAllowlist", "returnValues": { "operatorSetID": "0x123...", "operator": "0xabc..." } } ``` ``` ```APIDOC ## GET /isOperatorAllowed ### Description Checks whether a specific operator is currently allowed for a given operator set. ### Method GET ### Endpoint /isOperatorAllowed ### Parameters #### Path Parameters None #### Query Parameters - **operatorSet** (OperatorSet memory) - Required - The operator set to check against. - **operator** (address) - Required - The operator address to verify. ### Request Example ```json { "operatorSet": { "operatorSetID": "0x123...", "maxOperators": 100, "minOperators": 10 }, "operator": "0xabc..." } ``` ### Response #### Success Response (200) - **allowed** (bool) - `true` if the operator is allowed, `false` otherwise. #### Response Example ```json { "allowed": true } ``` ``` ```APIDOC ## GET /getAllowedOperators ### Description Retrieves an array of all operator addresses that are currently on the allowlist for a specified operator set. ### Method GET ### Endpoint /getAllowedOperators ### Parameters #### Path Parameters None #### Query Parameters - **operatorSet** (OperatorSet memory) - Required - The operator set for which to retrieve the allowlist. ### Request Example ```json { "operatorSet": { "operatorSetID": "0x123...", "maxOperators": 100, "minOperators": 10 } } ``` ### Response #### Success Response (200) - **allowedOperators** (address[]) - An array of addresses representing the operators on the allowlist. #### Response Example ```json { "allowedOperators": [ "0xabc...", "0xdef..." ] } ``` ```