@@ -3,7 +3,7 @@ pragma solidity ^0.8.12;
33
44import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol " ;
55import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol " ;
6- import {AVSDirectory } from "eigenlayer-contracts/src/contracts/core/AVSDirectory .sol " ;
6+ import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory .sol " ;
77import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol " ;
88import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol " ;
99import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol " ;
@@ -14,6 +14,7 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol";
1414import {BitmapUtils} from "./libraries/BitmapUtils.sol " ;
1515import {BN254} from "./libraries/BN254.sol " ;
1616import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol " ;
17+ import {QuorumBitmapHistoryLib} from "./libraries/QuorumBitmapHistoryLib.sol " ;
1718
1819import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol " ;
1920import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol " ;
@@ -58,9 +59,10 @@ contract RegistryCoordinator is
5859 IServiceManager _serviceManager ,
5960 IStakeRegistry _stakeRegistry ,
6061 IBLSApkRegistry _blsApkRegistry ,
61- IIndexRegistry _indexRegistry
62+ IIndexRegistry _indexRegistry ,
63+ IAVSDirectory _avsDirectory
6264 )
63- RegistryCoordinatorStorage (_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry)
65+ RegistryCoordinatorStorage (_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory )
6466 EIP712 ("AVSRegistryCoordinator " , "v0.0.1 " )
6567 {
6668 _disableInitializers ();
@@ -158,7 +160,7 @@ contract RegistryCoordinator is
158160
159161 require (
160162 numOperatorsPerQuorum[i] <= _quorumParams[quorumNumber].maxOperatorCount,
161- "RegistryCoordinator.registerOperator: operator count exceeds maximum "
163+ "RegistryCoordinator.registerOperator: operator exceeds max "
162164 );
163165 }
164166 }
@@ -333,7 +335,7 @@ contract RegistryCoordinator is
333335 // Prevent duplicate operators
334336 require (
335337 operator > prevOperatorAddress,
336- "RegistryCoordinator.updateOperatorsForQuorum: operators array must be sorted in ascending address order "
338+ "RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted "
337339 );
338340 }
339341
@@ -355,7 +357,7 @@ contract RegistryCoordinator is
355357 function updateSocket (string memory socket ) external {
356358 require (
357359 _operatorInfo[msg .sender ].status == OperatorStatus.REGISTERED,
358- "RegistryCoordinator.updateSocket: operator is not registered "
360+ "RegistryCoordinator.updateSocket: not registered "
359361 );
360362 emit OperatorSocketUpdate (_operatorInfo[msg .sender ].operatorId, socket);
361363 }
@@ -486,7 +488,7 @@ contract RegistryCoordinator is
486488 uint192 (BitmapUtils.orderedBytesArrayToBitmap (quorumNumbers, quorumCount));
487489 uint192 currentBitmap = _currentOperatorBitmap (operatorId);
488490 require (
489- ! quorumsToAdd.isEmpty (), "RegistryCoordinator._registerOperator: bitmap cannot be 0 "
491+ ! quorumsToAdd.isEmpty (), "RegistryCoordinator._registerOperator: bitmap empty "
490492 );
491493 require (
492494 quorumsToAdd.noBitsInCommon (currentBitmap),
@@ -515,9 +517,20 @@ contract RegistryCoordinator is
515517 OperatorInfo ({operatorId: operatorId, status: OperatorStatus.REGISTERED});
516518
517519 // Register the operator with the EigenLayer core contracts via this AVS's ServiceManager
518- serviceManager.registerOperatorToAVS (operator, operatorSignature);
520+ bool operatorSetAVS = avsDirectory.isOperatorSetAVS (address (serviceManager));
521+ if (operatorSetAVS){
522+ bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray (quorumsToAdd);
523+ uint32 [] memory operatorSetIds = new uint32 [](quorumBytes.length );
524+ for (uint256 i = 0 ; i < quorumBytes.length ; i++ ) {
525+ operatorSetIds[i] = uint8 (quorumBytes[i]);
526+ }
527+ serviceManager.registerOperatorToOperatorSets (operator, operatorSetIds, operatorSignature);
528+
529+ } else {
530+ serviceManager.registerOperatorToAVS (operator, operatorSignature);
531+ emit OperatorRegistered (operator, operatorId);
532+ }
519533
520- emit OperatorRegistered (operator, operatorId);
521534 }
522535
523536 // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry
@@ -534,7 +547,7 @@ contract RegistryCoordinator is
534547 * @dev Reverts if the caller is not the ejector
535548 */
536549 function _checkEjector () internal view {
537- require (msg .sender == ejector, "RegistryCoordinator.onlyEjector: caller is not the ejector " );
550+ require (msg .sender == ejector, "RegistryCoordinator.onlyEjector: not ejector " );
538551 }
539552
540553 /**
@@ -628,7 +641,7 @@ contract RegistryCoordinator is
628641 bytes32 operatorId = operatorInfo.operatorId;
629642 require (
630643 operatorInfo.status == OperatorStatus.REGISTERED,
631- "RegistryCoordinator._deregisterOperator: operator is not registered "
644+ "RegistryCoordinator._deregisterOperator: not registered "
632645 );
633646
634647 /**
@@ -647,19 +660,54 @@ contract RegistryCoordinator is
647660 );
648661 require (
649662 quorumsToRemove.isSubsetOf (currentBitmap),
650- "RegistryCoordinator._deregisterOperator: operator is not registered for specified quorums "
663+ "RegistryCoordinator._deregisterOperator: not registered for quorum "
651664 );
652665 uint192 newBitmap = uint192 (currentBitmap.minus (quorumsToRemove));
653666
654667 // Update operator's bitmap and status
655668 _updateOperatorBitmap ({operatorId: operatorId, newBitmap: newBitmap});
656669
657- // If the operator is no longer registered for any quorums, update their status and deregister
658- // them from the AVS via the EigenLayer core contracts
659- if (newBitmap.isEmpty ()) {
660- operatorInfo.status = OperatorStatus.DEREGISTERED;
661- serviceManager.deregisterOperatorFromAVS (operator);
662- emit OperatorDeregistered (operator, operatorId);
670+
671+ bool operatorSetAVS = IAVSDirectory (serviceManager.avsDirectory ()).isOperatorSetAVS (address (serviceManager));
672+ if (operatorSetAVS){
673+ bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray (quorumsToRemove);
674+ uint32 [] memory operatorSetIds = new uint32 [](quorumBytes.length );
675+ uint256 forceDeregistrationCount;
676+ for (uint256 i = 0 ; i < quorumBytes.length ; i++ ) {
677+ /// We need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory
678+ /// but hasnt yet been recorded in the middleware contracts
679+ if (! avsDirectory.isMember (operator, IAVSDirectory.OperatorSet (address (serviceManager), uint8 (quorumBytes[i])))){
680+ forceDeregistrationCount++ ;
681+ }
682+ operatorSetIds[i] = uint8 (quorumBytes[i]);
683+ }
684+
685+ /// Filter out forceDeregistration operator set Ids
686+ if (forceDeregistrationCount > 0 ){
687+ uint32 [] memory filteredOperatorSetIds = new uint32 [](operatorSetIds.length - forceDeregistrationCount);
688+ uint256 offset;
689+ for (uint256 i; i < operatorSetIds.length ; i++ ){
690+ if (avsDirectory.isMember (operator, IAVSDirectory.OperatorSet (address (serviceManager), operatorSetIds[i]))){
691+ filteredOperatorSetIds[i] = operatorSetIds[i+ offset];
692+ } else {
693+ offset++ ;
694+ }
695+ }
696+ serviceManager.deregisterOperatorFromOperatorSets (operator, filteredOperatorSetIds);
697+ } else {
698+ serviceManager.deregisterOperatorFromOperatorSets (operator, operatorSetIds);
699+
700+ }
701+
702+
703+ } else {
704+ // If the operator is no longer registered for any quorums, update their status and deregister
705+ // them from the AVS via the EigenLayer core contracts
706+ if (newBitmap.isEmpty ()) {
707+ operatorInfo.status = OperatorStatus.DEREGISTERED;
708+ serviceManager.deregisterOperatorFromAVS (operator);
709+ emit OperatorDeregistered (operator, operatorId);
710+ }
663711 }
664712
665713 // Deregister operator with each of the registry contracts
@@ -726,11 +774,11 @@ contract RegistryCoordinator is
726774 // make sure the salt hasn't been used already
727775 require (
728776 ! isChurnApproverSaltUsed[churnApproverSignature.salt],
729- "RegistryCoordinator._verifyChurnApproverSignature: churnApprover salt already used "
777+ "RegistryCoordinator._verifyChurnApproverSignature: salt spent "
730778 );
731779 require (
732780 churnApproverSignature.expiry >= block .timestamp ,
733- "RegistryCoordinator._verifyChurnApproverSignature: churnApprover signature expired "
781+ "RegistryCoordinator._verifyChurnApproverSignature: signature expired "
734782 );
735783
736784 // set salt used to true
@@ -780,7 +828,6 @@ contract RegistryCoordinator is
780828 indexRegistry.initializeQuorum (quorumNumber);
781829 blsApkRegistry.initializeQuorum (quorumNumber);
782830 // Check if the AVS has migrated to operator sets
783- AVSDirectory avsDirectory = AVSDirectory (serviceManager.avsDirectory ());
784831 if (avsDirectory.isOperatorSetAVS (address (serviceManager))) {
785832 // Create an operator set for the new quorum
786833 uint32 [] memory operatorSetIds = new uint32 [](1 );
@@ -794,50 +841,13 @@ contract RegistryCoordinator is
794841 * @param newBitmap is the most up-to-date set of bitmaps the operator is registered for
795842 */
796843 function _updateOperatorBitmap (bytes32 operatorId , uint192 newBitmap ) internal {
797- uint256 historyLength = _operatorBitmapHistory[operatorId].length ;
798-
799- if (historyLength == 0 ) {
800- // No prior bitmap history - push our first entry
801- _operatorBitmapHistory[operatorId].push (
802- QuorumBitmapUpdate ({
803- updateBlockNumber: uint32 (block .number ),
804- nextUpdateBlockNumber: 0 ,
805- quorumBitmap: newBitmap
806- })
807- );
808- } else {
809- // We have prior history - fetch our last-recorded update
810- QuorumBitmapUpdate storage lastUpdate =
811- _operatorBitmapHistory[operatorId][historyLength - 1 ];
812-
813- /**
814- * If the last update was made in the current block, update the entry.
815- * Otherwise, push a new entry and update the previous entry's "next" field
816- */
817- if (lastUpdate.updateBlockNumber == uint32 (block .number )) {
818- lastUpdate.quorumBitmap = newBitmap;
819- } else {
820- lastUpdate.nextUpdateBlockNumber = uint32 (block .number );
821- _operatorBitmapHistory[operatorId].push (
822- QuorumBitmapUpdate ({
823- updateBlockNumber: uint32 (block .number ),
824- nextUpdateBlockNumber: 0 ,
825- quorumBitmap: newBitmap
826- })
827- );
828- }
829- }
844+ QuorumBitmapHistoryLib.updateOperatorBitmap (_operatorBitmapHistory, operatorId, newBitmap);
830845 }
831846
832847 /// @notice Get the most recent bitmap for the operator, returning an empty bitmap if
833848 /// the operator is not registered.
834849 function _currentOperatorBitmap (bytes32 operatorId ) internal view returns (uint192 ) {
835- uint256 historyLength = _operatorBitmapHistory[operatorId].length ;
836- if (historyLength == 0 ) {
837- return 0 ;
838- } else {
839- return _operatorBitmapHistory[operatorId][historyLength - 1 ].quorumBitmap;
840- }
850+ return QuorumBitmapHistoryLib.currentOperatorBitmap (_operatorBitmapHistory, operatorId);
841851 }
842852
843853 /**
@@ -849,21 +859,7 @@ contract RegistryCoordinator is
849859 uint32 blockNumber ,
850860 bytes32 operatorId
851861 ) internal view returns (uint32 index ) {
852- uint256 length = _operatorBitmapHistory[operatorId].length ;
853-
854- // Traverse the operator's bitmap history in reverse, returning the first index
855- // corresponding to an update made before or at `blockNumber`
856- for (uint256 i = 0 ; i < length; i++ ) {
857- index = uint32 (length - i - 1 );
858-
859- if (_operatorBitmapHistory[operatorId][index].updateBlockNumber <= blockNumber) {
860- return index;
861- }
862- }
863-
864- revert (
865- "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number "
866- );
862+ return QuorumBitmapHistoryLib.getQuorumBitmapIndexAtBlockNumber (_operatorBitmapHistory,blockNumber, operatorId);
867863 }
868864
869865 function _setOperatorSetParams (
@@ -932,11 +928,7 @@ contract RegistryCoordinator is
932928 uint32 blockNumber ,
933929 bytes32 [] memory operatorIds
934930 ) external view returns (uint32 [] memory ) {
935- uint32 [] memory indices = new uint32 [](operatorIds.length );
936- for (uint256 i = 0 ; i < operatorIds.length ; i++ ) {
937- indices[i] = _getQuorumBitmapIndexAtBlockNumber (blockNumber, operatorIds[i]);
938- }
939- return indices;
931+ return QuorumBitmapHistoryLib.getQuorumBitmapIndicesAtBlockNumber (_operatorBitmapHistory, blockNumber, operatorIds);
940932 }
941933
942934 /**
@@ -950,24 +942,7 @@ contract RegistryCoordinator is
950942 uint32 blockNumber ,
951943 uint256 index
952944 ) external view returns (uint192 ) {
953- QuorumBitmapUpdate memory quorumBitmapUpdate = _operatorBitmapHistory[operatorId][index];
954-
955- /**
956- * Validate that the update is valid for the given blockNumber:
957- * - blockNumber should be >= the update block number
958- * - the next update block number should be either 0 or strictly greater than blockNumber
959- */
960- require (
961- blockNumber >= quorumBitmapUpdate.updateBlockNumber,
962- "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber "
963- );
964- require (
965- quorumBitmapUpdate.nextUpdateBlockNumber == 0
966- || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber,
967- "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber "
968- );
969-
970- return quorumBitmapUpdate.quorumBitmap;
945+ return QuorumBitmapHistoryLib.getQuorumBitmapAtBlockNumberByIndex (_operatorBitmapHistory, operatorId, blockNumber, index);
971946 }
972947
973948 /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history
0 commit comments