@@ -15,6 +15,7 @@ import {BitmapUtils} from "./libraries/BitmapUtils.sol";
15
15
import {SlashingRegistryCoordinator} from "./SlashingRegistryCoordinator.sol " ;
16
16
import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol " ;
17
17
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol " ;
18
+ import {RegistryCoordinatorStorage} from "./RegistryCoordinatorStorage.sol " ;
18
19
19
20
/**
20
21
* @title A `RegistryCoordinator` that has three registries:
@@ -24,12 +25,9 @@ import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/Ownabl
24
25
*
25
26
* @author Layr Labs, Inc.
26
27
*/
27
- contract RegistryCoordinator is IRegistryCoordinator , SlashingRegistryCoordinator {
28
+ contract RegistryCoordinator is RegistryCoordinatorStorage {
28
29
using BitmapUtils for * ;
29
30
30
- /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts
31
- IServiceManager public immutable serviceManager;
32
-
33
31
constructor (
34
32
IServiceManager _serviceManager ,
35
33
IStakeRegistry _stakeRegistry ,
@@ -39,17 +37,16 @@ contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinato
39
37
IAllocationManager _allocationManager ,
40
38
IPauserRegistry _pauserRegistry
41
39
)
42
- SlashingRegistryCoordinator (
40
+ RegistryCoordinatorStorage (
41
+ _serviceManager,
43
42
_stakeRegistry,
44
43
_blsApkRegistry,
45
44
_indexRegistry,
46
45
_socketRegistry,
47
46
_allocationManager,
48
47
_pauserRegistry
49
48
)
50
- {
51
- serviceManager = _serviceManager;
52
- }
49
+ {}
53
50
54
51
/**
55
52
*
@@ -64,44 +61,28 @@ contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinato
64
61
IBLSApkRegistryTypes.PubkeyRegistrationParams memory params ,
65
62
SignatureWithSaltAndExpiry memory operatorSignature
66
63
) external onlyWhenNotPaused (PAUSED_REGISTER_OPERATOR) {
67
- require (! m2QuorumsDisabled, M2QuorumsAlreadyDisabled ());
68
- /**
69
- * If the operator has NEVER registered a pubkey before, use `params` to register
70
- * their pubkey in blsApkRegistry
71
- *
72
- * If the operator HAS registered a pubkey, `params` is ignored and the pubkey hash
73
- * (operatorId) is fetched instead
74
- */
75
- bytes32 operatorId = _getOrCreateOperatorId (msg .sender , params);
76
-
77
- // Register the operator in each of the registry contracts and update the operator's
78
- // quorum bitmap and registration status
79
- uint32 [] memory numOperatorsPerQuorum = _registerOperator ({
64
+ require (! isM2QuorumRegistrationDisabled, M2QuorumRegistrationIsDisabled ());
65
+ require (
66
+ quorumNumbers.orderedBytesArrayToBitmap ().isSubsetOf (m2QuorumBitmap ()),
67
+ OnlyM2QuorumsAllowed ()
68
+ );
69
+
70
+ // Check if the operator has registered before
71
+ bool operatorRegisteredBefore =
72
+ _operatorInfo[msg .sender ].status == OperatorStatus.REGISTERED;
73
+
74
+ // register the operator with the registry coordinator
75
+ _registerOperator ({
80
76
operator: msg .sender ,
81
- operatorId: operatorId ,
77
+ operatorId: _getOrCreateOperatorId ( msg . sender , params) ,
82
78
quorumNumbers: quorumNumbers,
83
- socket: socket
84
- }).numOperatorsPerQuorum;
85
-
86
- // For each quorum, validate that the new operator count does not exceed the maximum
87
- // (If it does, an operator needs to be replaced -- see `registerOperatorWithChurn`)
88
- for (uint256 i = 0 ; i < quorumNumbers.length ; i++ ) {
89
- uint8 quorumNumber = uint8 (quorumNumbers[i]);
90
-
91
- require (
92
- numOperatorsPerQuorum[i] <= _quorumParams[quorumNumber].maxOperatorCount,
93
- MaxQuorumsReached ()
94
- );
95
- }
96
-
97
- // If the operator wasn't registered for any quorums, update their status
98
- // and register them with this AVS in EigenLayer core (DelegationManager)
99
- if (_operatorInfo[msg .sender ].status != OperatorStatus.REGISTERED) {
100
- _operatorInfo[msg .sender ] =
101
- OperatorInfo ({operatorId: operatorId, status: OperatorStatus.REGISTERED});
79
+ socket: socket,
80
+ checkMaxOperatorCount: true
81
+ });
102
82
83
+ // If the operator has never registered before, register them with the AVSDirectory
84
+ if (! operatorRegisteredBefore) {
103
85
serviceManager.registerOperatorToAVS (msg .sender , operatorSignature);
104
- emit OperatorRegistered (msg .sender , operatorId);
105
86
}
106
87
}
107
88
@@ -114,34 +95,29 @@ contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinato
114
95
SignatureWithSaltAndExpiry memory churnApproverSignature ,
115
96
SignatureWithSaltAndExpiry memory operatorSignature
116
97
) external onlyWhenNotPaused (PAUSED_REGISTER_OPERATOR) {
117
- require (! m2QuorumsDisabled, M2QuorumsAlreadyDisabled ());
98
+ require (! isM2QuorumRegistrationDisabled, M2QuorumRegistrationIsDisabled ());
99
+ require (
100
+ quorumNumbers.orderedBytesArrayToBitmap ().isSubsetOf (m2QuorumBitmap ()),
101
+ OnlyM2QuorumsAllowed ()
102
+ );
118
103
119
- /**
120
- * If the operator has NEVER registered a pubkey before, use `params` to register
121
- * their pubkey in blsApkRegistry
122
- *
123
- * If the operator HAS registered a pubkey, `params` is ignored and the pubkey hash
124
- * (operatorId) is fetched instead
125
- */
126
- bytes32 operatorId = _getOrCreateOperatorId (msg .sender , params);
104
+ // Check if the operator has registered before
105
+ bool operatorRegisteredBefore =
106
+ _operatorInfo[msg .sender ].status == OperatorStatus.REGISTERED;
127
107
108
+ // register the operator with the registry coordinator with churn
128
109
_registerOperatorWithChurn ({
129
110
operator: msg .sender ,
130
- operatorId: operatorId ,
111
+ operatorId: _getOrCreateOperatorId ( msg . sender , params) ,
131
112
quorumNumbers: quorumNumbers,
132
113
socket: socket,
133
114
operatorKickParams: operatorKickParams,
134
115
churnApproverSignature: churnApproverSignature
135
116
});
136
117
137
- // If the operator wasn't registered for any quorums, update their status
138
- // and register them with this AVS in EigenLayer core (DelegationManager)
139
- if (_operatorInfo[msg .sender ].status != OperatorStatus.REGISTERED) {
140
- _operatorInfo[msg .sender ] =
141
- OperatorInfo ({operatorId: operatorId, status: OperatorStatus.REGISTERED});
142
-
118
+ // If the operator has never registered before, register them with the AVSDirectory
119
+ if (! operatorRegisteredBefore) {
143
120
serviceManager.registerOperatorToAVS (msg .sender , operatorSignature);
144
- emit OperatorRegistered (msg .sender , operatorId);
145
121
}
146
122
}
147
123
@@ -150,56 +126,78 @@ contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinato
150
126
bytes memory quorumNumbers
151
127
) external override onlyWhenNotPaused (PAUSED_DEREGISTER_OPERATOR) {
152
128
// Check that the quorum numbers are M2 quorums
153
- for ( uint256 i = 0 ; i < quorumNumbers. length ; i ++ ) {
154
- require (
155
- ! operatorSetsEnabled || _isM2Quorum ( uint8 (quorumNumbers[i])), OperatorSetQuorum ()
156
- );
157
- }
129
+ require (
130
+ quorumNumbers. orderedBytesArrayToBitmap (). isSubsetOf ( m2QuorumBitmap ()),
131
+ OnlyM2QuorumsAllowed ()
132
+ );
133
+
158
134
_deregisterOperator ({operator: msg .sender , quorumNumbers: quorumNumbers});
159
135
}
160
136
161
137
/// @inheritdoc IRegistryCoordinator
162
- function enableOperatorSets () external onlyOwner {
163
- require (! operatorSetsEnabled, OperatorSetsAlreadyEnabled ());
164
-
165
- // Set the bitmap for M2 quorums
166
- M2quorumBitmap = _getQuorumBitmap (quorumCount);
138
+ function disableM2QuorumRegistration () external onlyOwner {
139
+ require (! isM2QuorumRegistrationDisabled, M2QuorumRegistrationIsDisabled ());
167
140
168
- // Enable operator sets mode
169
- operatorSetsEnabled = true ;
141
+ isM2QuorumRegistrationDisabled = true ;
170
142
171
- emit OperatorSetsEnabled ();
143
+ emit M2QuorumRegistrationDisabled ();
172
144
}
173
145
174
- /// @inheritdoc IRegistryCoordinator
175
- function disableM2QuorumRegistration () external onlyOwner {
176
- require (operatorSetsEnabled, OperatorSetsNotEnabled ());
146
+ /**
147
+ *
148
+ * INTERNAL FUNCTIONS
149
+ *
150
+ */
177
151
178
- m2QuorumsDisabled = true ;
152
+ /// @dev override the _forceDeregisterOperator function to handle M2 quorum deregistration
153
+ function _forceDeregisterOperator (
154
+ address operator ,
155
+ bytes memory quorumNumbers
156
+ ) internal virtual override {
157
+ // filter out M2 quorums from the quorum numbers
158
+ uint256 operatorSetBitmap =
159
+ quorumNumbers.orderedBytesArrayToBitmap ().minus (m2QuorumBitmap ());
160
+ if (! operatorSetBitmap.isEmpty ()) {
161
+ // call the parent _forceDeregisterOperator function for operator sets quorums
162
+ super ._forceDeregisterOperator (operator, operatorSetBitmap.bitmapToBytesArray ());
163
+ }
164
+ }
179
165
180
- emit M2QuorumsDisabled ();
166
+ /// @dev Hook to prevent any new quorums from being created if operator sets are not enabled
167
+ function _beforeCreateQuorum (
168
+ uint8
169
+ ) internal virtual override {
170
+ // If operator sets are not enabled, set the m2 quorum bitmap to the current m2 quorum bitmap
171
+ // and enable operator sets
172
+ if (! operatorSetsEnabled) {
173
+ _m2QuorumBitmap = m2QuorumBitmap ();
174
+ operatorSetsEnabled = true ;
175
+ }
181
176
}
182
177
183
178
/// @dev Hook to allow for any post-deregister logic
184
179
function _afterDeregisterOperator (
185
180
address operator ,
186
- bytes32 operatorId ,
187
- bytes memory quorumNumbers ,
181
+ bytes32 ,
182
+ bytes memory ,
188
183
uint192 newBitmap
189
184
) internal virtual override {
190
- uint256 operatorM2QuorumBitmap = newBitmap.minus (M2quorumBitmap);
185
+ // Bitmap representing all quorums including M2 and OperatorSet quorums
186
+ uint256 totalQuorumBitmap = _getTotalQuorumBitmap ();
187
+ // Bitmap representing only OperatorSet quorums. Equal to 0 if operatorSets not enabled
188
+ uint256 operatorSetQuorumBitmap = totalQuorumBitmap.minus (m2QuorumBitmap ());
189
+ // Operators updated M2 quorum bitmap, clear all the bits of operatorSetQuorumBitmap which gives the
190
+ // operator's M2 quorum bitmap.
191
+ uint256 operatorM2QuorumBitmap = newBitmap.minus (operatorSetQuorumBitmap);
191
192
// If the operator is no longer registered for any M2 quorums, update their status and deregister
192
193
// them from the AVS via the EigenLayer core contracts
193
194
if (operatorM2QuorumBitmap.isEmpty ()) {
194
195
serviceManager.deregisterOperatorFromAVS (operator);
195
196
}
196
197
}
197
198
198
- /// @dev Returns a bitmap with all bits set up to `quorumCount`. Used for bit-masking quorum numbers
199
- /// and differentiating between operator sets and M2 quorums
200
- function _getQuorumBitmap (
201
- uint256 quorumCount
202
- ) internal pure returns (uint256 ) {
199
+ /// @notice Return bitmap representing all quorums(Legacy M2 and OperatorSet) quorums
200
+ function _getTotalQuorumBitmap () internal view returns (uint256 ) {
203
201
// This creates a number where all bits up to quorumCount are set to 1
204
202
// For example:
205
203
// quorumCount = 3 -> 0111 (7 in decimal)
@@ -208,6 +206,38 @@ contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinato
208
206
return (1 << quorumCount) - 1 ;
209
207
}
210
208
209
+ /// @notice Returns true if the quorum number is an M2 quorum
210
+ /// @dev We use bitwise and to check if the quorum number is an M2 quorum
211
+ function _isM2Quorum (
212
+ uint8 quorumNumber
213
+ ) internal view returns (bool ) {
214
+ return m2QuorumBitmap ().isSet (quorumNumber);
215
+ }
216
+
217
+ /**
218
+ *
219
+ * VIEW FUNCTIONS
220
+ *
221
+ */
222
+
223
+ /// @dev Returns a bitmap with all bits set up to `quorumCount`. Used for bit-masking quorum numbers
224
+ /// and differentiating between operator sets and M2 quorums
225
+ function m2QuorumBitmap () public view returns (uint256 ) {
226
+ // If operator sets are enabled, return the current m2 quorum bitmap
227
+ if (operatorSetsEnabled) {
228
+ return _m2QuorumBitmap;
229
+ }
230
+
231
+ return _getTotalQuorumBitmap ();
232
+ }
233
+
234
+ /// @notice Returns true if the quorum number is an M2 quorum
235
+ function isM2Quorum (
236
+ uint8 quorumNumber
237
+ ) external view returns (bool ) {
238
+ return _isM2Quorum (quorumNumber);
239
+ }
240
+
211
241
/**
212
242
* @notice Returns the message hash that an operator must sign to register their BLS public key.
213
243
* @param operator is the address of the operator registering their BLS public key
@@ -217,14 +247,4 @@ contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinato
217
247
) public view returns (bytes32 ) {
218
248
return _hashTypedDataV4 (keccak256 (abi.encode (PUBKEY_REGISTRATION_TYPEHASH, operator)));
219
249
}
220
-
221
- /// @dev need to override function here since its defined in both these contracts
222
- function owner ()
223
- public
224
- view
225
- override (SlashingRegistryCoordinator, ISlashingRegistryCoordinator)
226
- returns (address )
227
- {
228
- return OwnableUpgradeable.owner ();
229
- }
230
250
}
0 commit comments