@@ -64,15 +64,25 @@ contract AllocationManager is
64
64
function slashOperator (
65
65
address avs ,
66
66
SlashingParams calldata params
67
- ) external onlyWhenNotPaused (PAUSED_OPERATOR_SLASHING) checkCanCall (avs) {
67
+ )
68
+ external
69
+ onlyWhenNotPaused (PAUSED_OPERATOR_SLASHING)
70
+ checkCanCall (avs)
71
+ returns (uint256 slashId , uint256 [] memory shares )
72
+ {
68
73
// Check that the operator set exists and the operator is registered to it
69
74
OperatorSet memory operatorSet = OperatorSet (avs, params.operatorSetId);
70
- require (params.strategies.length == params.wadsToSlash.length , InputArrayLengthMismatch () );
71
- require (_operatorSets[ operatorSet.avs]. contains (operatorSet.id), InvalidOperatorSet () );
75
+ _checkArrayLengthsMatch (params.strategies.length , params.wadsToSlash.length );
76
+ _checkIsOperatorSet ( operatorSet);
72
77
require (isOperatorSlashable (params.operator, operatorSet), OperatorNotSlashable ());
73
78
74
79
uint256 [] memory wadSlashed = new uint256 [](params.strategies.length );
75
80
81
+ // Increment the slash count for the operator set, first `slashId` equals 1.
82
+ slashId = ++ _slashCount[operatorSet.key ()];
83
+ // Initialize the shares array.
84
+ shares = new uint256 [](params.strategies.length );
85
+
76
86
// For each strategy in the operator set, slash any existing allocation
77
87
for (uint256 i = 0 ; i < params.strategies.length ; i++ ) {
78
88
// Check that `strategies` is in ascending order.
@@ -155,7 +165,7 @@ contract AllocationManager is
155
165
) external onlyWhenNotPaused (PAUSED_MODIFY_ALLOCATIONS) {
156
166
// Check that the caller is allowed to modify allocations on behalf of the operator
157
167
// We do not use a modifier to avoid `stack too deep` errors
158
- require ( _checkCanCall (operator), InvalidCaller () );
168
+ _checkCanCall (operator);
159
169
160
170
// Check that the operator exists and has configured an allocation delay
161
171
uint32 operatorAllocationDelay;
@@ -166,15 +176,15 @@ contract AllocationManager is
166
176
}
167
177
168
178
for (uint256 i = 0 ; i < params.length ; i++ ) {
169
- require (params[i].strategies.length == params[i].newMagnitudes.length , InputArrayLengthMismatch () );
179
+ _checkArrayLengthsMatch (params[i].strategies.length , params[i].newMagnitudes.length );
170
180
171
181
// Check that the operator set exists and get the operator's registration status
172
182
// Operators do not need to be registered for an operator set in order to allocate
173
183
// slashable magnitude to the set. In fact, it is expected that operators will
174
184
// allocate magnitude before registering, as AVS's will likely only accept
175
185
// registrations from operators that are already slashable.
176
186
OperatorSet memory operatorSet = params[i].operatorSet;
177
- require (_operatorSets[ operatorSet.avs]. contains (operatorSet.id), InvalidOperatorSet () );
187
+ _checkIsOperatorSet ( operatorSet);
178
188
179
189
bool _isOperatorSlashable = isOperatorSlashable (operator, operatorSet);
180
190
@@ -246,8 +256,7 @@ contract AllocationManager is
246
256
IStrategy[] calldata strategies ,
247
257
uint16 [] calldata numToClear
248
258
) external onlyWhenNotPaused (PAUSED_MODIFY_ALLOCATIONS) {
249
- require (strategies.length == numToClear.length , InputArrayLengthMismatch ());
250
-
259
+ _checkArrayLengthsMatch (strategies.length , numToClear.length );
251
260
for (uint256 i = 0 ; i < strategies.length ; ++ i) {
252
261
_clearDeallocationQueue ({operator: operator, strategy: strategies[i], numToClear: numToClear[i]});
253
262
}
@@ -258,13 +267,13 @@ contract AllocationManager is
258
267
address operator ,
259
268
RegisterParams calldata params
260
269
) external onlyWhenNotPaused (PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION) checkCanCall (operator) {
261
- // Check that the operator exists
262
- require (delegation. isOperator ( operator), InvalidOperator () );
270
+ // Check if the operator has registered.
271
+ _checkIsOperator ( operator);
263
272
264
273
for (uint256 i = 0 ; i < params.operatorSetIds.length ; i++ ) {
265
274
// Check the operator set exists and the operator is not currently registered to it
266
275
OperatorSet memory operatorSet = OperatorSet (params.avs, params.operatorSetIds[i]);
267
- require (_operatorSets[ operatorSet.avs]. contains (operatorSet.id), InvalidOperatorSet () );
276
+ _checkIsOperatorSet ( operatorSet);
268
277
require (! isOperatorSlashable (operator, operatorSet), AlreadyMemberOfSet ());
269
278
270
279
// Add operator to operator set
@@ -285,12 +294,12 @@ contract AllocationManager is
285
294
DeregisterParams calldata params
286
295
) external onlyWhenNotPaused (PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION) {
287
296
// Check that the caller is either authorized on behalf of the operator or AVS
288
- require (_checkCanCall (params.operator) || _checkCanCall (params.avs), InvalidCaller ());
297
+ require (_canCall (params.operator) || _canCall (params.avs), InvalidPermissions ());
289
298
290
299
for (uint256 i = 0 ; i < params.operatorSetIds.length ; i++ ) {
291
300
// Check the operator set exists and the operator is registered to it
292
301
OperatorSet memory operatorSet = OperatorSet (params.avs, params.operatorSetIds[i]);
293
- require (_operatorSets[params.avs]. contains ( operatorSet.id), InvalidOperatorSet () );
302
+ _checkIsOperatorSet ( operatorSet);
294
303
require (registrationStatus[params.operator][operatorSet.key ()].registered, NotMemberOfSet ());
295
304
296
305
// Remove operator from operator set
@@ -313,8 +322,8 @@ contract AllocationManager is
313
322
/// @inheritdoc IAllocationManager
314
323
function setAllocationDelay (address operator , uint32 delay ) external {
315
324
if (msg .sender != address (delegation)) {
316
- require ( _checkCanCall (operator), InvalidCaller () );
317
- require (delegation. isOperator ( operator), InvalidOperator () );
325
+ _checkCanCall (operator);
326
+ _checkIsOperator ( operator);
318
327
}
319
328
_setAllocationDelay (operator, delay);
320
329
}
@@ -330,31 +339,28 @@ contract AllocationManager is
330
339
331
340
/// @inheritdoc IAllocationManager
332
341
function updateAVSMetadataURI (address avs , string calldata metadataURI ) external checkCanCall (avs) {
333
- if (! _avsRegisteredMetadata[avs]) {
334
- _avsRegisteredMetadata[avs] = true ;
335
- }
336
-
342
+ if (! _avsRegisteredMetadata[avs]) _avsRegisteredMetadata[avs] = true ;
337
343
emit AVSMetadataURIUpdated (avs, metadataURI);
338
344
}
339
345
340
346
/// @inheritdoc IAllocationManager
341
347
function createOperatorSets (address avs , CreateSetParams[] calldata params ) external checkCanCall (avs) {
342
- // Check that the AVS exists and has registered metadata
343
348
require (_avsRegisteredMetadata[avs], NonexistentAVSMetadata ());
344
-
345
349
for (uint256 i = 0 ; i < params.length ; i++ ) {
346
- OperatorSet memory operatorSet = OperatorSet (avs, params[i].operatorSetId);
347
-
348
- // Create the operator set, ensuring it does not already exist
349
- require (_operatorSets[avs].add (operatorSet.id), InvalidOperatorSet ());
350
- emit OperatorSetCreated (OperatorSet (avs, operatorSet.id));
350
+ _createOperatorSet (avs, params[i], DEFAULT_BURN_ADDRESS);
351
+ }
352
+ }
351
353
352
- // Add strategies to the operator set
353
- bytes32 operatorSetKey = operatorSet.key ();
354
- for (uint256 j = 0 ; j < params[i].strategies.length ; j++ ) {
355
- _operatorSetStrategies[operatorSetKey].add (address (params[i].strategies[j]));
356
- emit StrategyAddedToOperatorSet (operatorSet, params[i].strategies[j]);
357
- }
354
+ /// @inheritdoc IAllocationManager
355
+ function createRedistributingOperatorSets (
356
+ address avs ,
357
+ CreateSetParams[] calldata params ,
358
+ address [] calldata redistributionRecipients
359
+ ) external checkCanCall (avs) {
360
+ _checkArrayLengthsMatch (params.length , redistributionRecipients.length );
361
+ require (_avsRegisteredMetadata[avs], NonexistentAVSMetadata ());
362
+ for (uint256 i = 0 ; i < params.length ; i++ ) {
363
+ _createOperatorSet (avs, params[i], redistributionRecipients[i]);
358
364
}
359
365
}
360
366
@@ -365,10 +371,8 @@ contract AllocationManager is
365
371
IStrategy[] calldata strategies
366
372
) external checkCanCall (avs) {
367
373
OperatorSet memory operatorSet = OperatorSet (avs, operatorSetId);
374
+ _checkIsOperatorSet (operatorSet);
368
375
bytes32 operatorSetKey = operatorSet.key ();
369
-
370
- require (_operatorSets[avs].contains (operatorSet.id), InvalidOperatorSet ());
371
-
372
376
for (uint256 i = 0 ; i < strategies.length ; i++ ) {
373
377
require (_operatorSetStrategies[operatorSetKey].add (address (strategies[i])), StrategyAlreadyInOperatorSet ());
374
378
emit StrategyAddedToOperatorSet (operatorSet, strategies[i]);
@@ -382,8 +386,7 @@ contract AllocationManager is
382
386
IStrategy[] calldata strategies
383
387
) external checkCanCall (avs) {
384
388
OperatorSet memory operatorSet = OperatorSet (avs, operatorSetId);
385
- require (_operatorSets[avs].contains (operatorSet.id), InvalidOperatorSet ());
386
-
389
+ _checkIsOperatorSet (operatorSet);
387
390
bytes32 operatorSetKey = operatorSet.key ();
388
391
for (uint256 i = 0 ; i < strategies.length ; i++ ) {
389
392
require (_operatorSetStrategies[operatorSetKey].remove (address (strategies[i])), StrategyNotInOperatorSet ());
@@ -397,6 +400,41 @@ contract AllocationManager is
397
400
*
398
401
*/
399
402
403
+ /**
404
+ * @notice Creates a new operator set for an AVS.
405
+ * @param avs The AVS address that owns the operator set.
406
+ * @param params The parameters for creating the operator set.
407
+ * @param redistributionRecipient Address to receive redistributed funds when operators are slashed.
408
+ * @dev If `redistributionRecipient` is address(0), the operator set is considered non-redistributing
409
+ * and slashed funds are sent to the `DEFAULT_BURN_ADDRESS`.
410
+ * @dev Providing `BEACONCHAIN_ETH_STRAT` as a strategy will revert since it's not currently supported.
411
+ */
412
+ function _createOperatorSet (
413
+ address avs ,
414
+ CreateSetParams calldata params ,
415
+ address redistributionRecipient
416
+ ) internal {
417
+ OperatorSet memory operatorSet = OperatorSet (avs, params.operatorSetId);
418
+
419
+ // Create the operator set, ensuring it does not already exist.
420
+ require (_operatorSets[avs].add (operatorSet.id), InvalidOperatorSet ());
421
+ emit OperatorSetCreated (operatorSet);
422
+
423
+ bool isRedistributing = redistributionRecipient != DEFAULT_BURN_ADDRESS;
424
+
425
+ if (isRedistributing) {
426
+ _redistributionRecipients[operatorSet.key ()] = redistributionRecipient;
427
+ emit RedistributionAddressSet (operatorSet, redistributionRecipient);
428
+ }
429
+
430
+ // Add strategies to the operator set
431
+ for (uint256 j = 0 ; j < params.strategies.length ; j++ ) {
432
+ if (isRedistributing && params.strategies[j] == BEACONCHAIN_ETH_STRAT) revert InvalidStrategy ();
433
+ _operatorSetStrategies[operatorSet.key ()].add (address (params.strategies[j]));
434
+ emit StrategyAddedToOperatorSet (operatorSet, params.strategies[j]);
435
+ }
436
+ }
437
+
400
438
/**
401
439
* @dev Clear one or more pending deallocations to a strategy's allocated magnitude
402
440
* @param operator the operator whose pending deallocations will be cleared
@@ -605,6 +643,25 @@ contract AllocationManager is
605
643
return uint256 (int256 (int128 (uint128 (a)) + b)).toUint64 ();
606
644
}
607
645
646
+ /// @dev Reverts if the operator set does not exist.
647
+ function _checkIsOperatorSet (
648
+ OperatorSet memory operatorSet
649
+ ) internal view {
650
+ require (_operatorSets[operatorSet.avs].contains (operatorSet.id), InvalidOperatorSet ());
651
+ }
652
+
653
+ /// @dev Reverts if the provided arrays have different lengths.
654
+ function _checkArrayLengthsMatch (uint256 left , uint256 right ) internal pure {
655
+ require (left == right, InputArrayLengthMismatch ());
656
+ }
657
+
658
+ /// @dev Reverts if the operator is not registered.
659
+ function _checkIsOperator (
660
+ address operator
661
+ ) internal view {
662
+ require (delegation.isOperator (operator), InvalidOperator ());
663
+ }
664
+
608
665
/**
609
666
*
610
667
* VIEW FUNCTIONS
@@ -905,4 +962,27 @@ contract AllocationManager is
905
962
// less than or equal to
906
963
return status.registered || block .number <= status.slashableUntil;
907
964
}
965
+
966
+ /// @inheritdoc IAllocationManager
967
+ function getRedistributionRecipient (
968
+ OperatorSet memory operatorSet
969
+ ) external view returns (address ) {
970
+ // Load the redistribution recipient and return it if set, otherwise return the default burn address.
971
+ address redistributionRecipient = _redistributionRecipients[operatorSet.key ()];
972
+ return redistributionRecipient == address (0 ) ? DEFAULT_BURN_ADDRESS : redistributionRecipient;
973
+ }
974
+
975
+ /// @inheritdoc IAllocationManager
976
+ function isRedistributingOperatorSet (
977
+ OperatorSet memory operatorSet
978
+ ) external view returns (bool ) {
979
+ return _redistributionRecipients[operatorSet.key ()] != address (0 );
980
+ }
981
+
982
+ /// @inheritdoc IAllocationManager
983
+ function getSlashCount (
984
+ OperatorSet memory operatorSet
985
+ ) external view returns (uint256 ) {
986
+ return _slashCount[operatorSet.key ()];
987
+ }
908
988
}
0 commit comments