|
2 | 2 | pragma solidity ^0.8.27;
|
3 | 3 |
|
4 | 4 | import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol";
|
5 |
| -import {IAllocationManager} from |
6 |
| - "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; |
| 5 | +import { |
| 6 | + IAllocationManager, |
| 7 | + OperatorSet |
| 8 | +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; |
7 | 9 | import {IBLSApkRegistry, IBLSApkRegistryTypes} from "./interfaces/IBLSApkRegistry.sol";
|
8 | 10 | import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol";
|
9 | 11 | import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol";
|
@@ -200,6 +202,44 @@ contract RegistryCoordinator is RegistryCoordinatorStorage {
|
200 | 202 | }
|
201 | 203 | }
|
202 | 204 |
|
| 205 | + /** |
| 206 | + * @dev Helper function to update operator stakes and deregister loiterers |
| 207 | + * Loiterers are AVS registered operators who have force deregistered from the OperatorSet/quorum |
| 208 | + * in the core EigenLayer contract AllocationManager but not deregistered from the OperatorSet/quorum |
| 209 | + * in this contract. Potentially due to out of gas errors in the deregistration callback. This function |
| 210 | + * will handle that edge case by deregistering the operator from the AVS if they are no longer registered |
| 211 | + * in the AllocationManager. |
| 212 | + */ |
| 213 | + function _updateStakesAndDeregisterLoiterers( |
| 214 | + address[] memory operators, |
| 215 | + bytes32[] memory operatorIds, |
| 216 | + uint8 quorumNumber |
| 217 | + ) internal virtual override { |
| 218 | + bytes memory singleQuorumNumber = new bytes(1); |
| 219 | + singleQuorumNumber[0] = bytes1(quorumNumber); |
| 220 | + bool[] memory doesNotMeetStakeThreshold = |
| 221 | + stakeRegistry.updateOperatorsStake(operators, operatorIds, quorumNumber); |
| 222 | + for (uint256 j = 0; j < operators.length; ++j) { |
| 223 | + // whether the operator is registered in the core EigenLayer contract AllocationManager |
| 224 | + bool registeredInCore = allocationManager.isMemberOfOperatorSet( |
| 225 | + operators[j], OperatorSet({avs: accountIdentifier, id: uint32(quorumNumber)}) |
| 226 | + ); |
| 227 | + |
| 228 | + // If the operator does not have the minimum stake, they need to be force deregistered. |
| 229 | + // Additionally, it is possible for an operator to have deregistered from an OperatorSet |
| 230 | + // in the core EigenLayer contract AllocationManager but not have the deregistration |
| 231 | + // callback succeed here in `deregisterOperator` due to out of gas errors. If that is the case, |
| 232 | + // we need to deregister the operator from the OperatorSet in this contract |
| 233 | + if (doesNotMeetStakeThreshold[j] || (!registeredInCore && !_isM2Quorum(quorumNumber))) { |
| 234 | + _deregisterOperator({ |
| 235 | + operator: operators[j], |
| 236 | + quorumNumbers: singleQuorumNumber, |
| 237 | + shouldForceDeregister: registeredInCore && !_isM2Quorum(quorumNumber) |
| 238 | + }); |
| 239 | + } |
| 240 | + } |
| 241 | + } |
| 242 | + |
203 | 243 | /// @notice Return bitmap representing all quorums(Legacy M2 and OperatorSet) quorums
|
204 | 244 | function _getTotalQuorumBitmap() internal view returns (uint256) {
|
205 | 245 | // This creates a number where all bits up to quorumCount are set to 1
|
|
0 commit comments