@@ -64,15 +64,25 @@ contract AllocationManager is
6464 function slashOperator (
6565 address avs ,
6666 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+ {
6873 // Check that the operator set exists and the operator is registered to it
6974 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);
7277 require (isOperatorSlashable (params.operator, operatorSet), OperatorNotSlashable ());
7378
7479 uint256 [] memory wadSlashed = new uint256 [](params.strategies.length );
7580
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+
7686 // For each strategy in the operator set, slash any existing allocation
7787 for (uint256 i = 0 ; i < params.strategies.length ; i++ ) {
7888 // Check that `strategies` is in ascending order.
@@ -155,7 +165,7 @@ contract AllocationManager is
155165 ) external onlyWhenNotPaused (PAUSED_MODIFY_ALLOCATIONS) {
156166 // Check that the caller is allowed to modify allocations on behalf of the operator
157167 // We do not use a modifier to avoid `stack too deep` errors
158- require ( _checkCanCall (operator), InvalidCaller () );
168+ _checkCanCall (operator);
159169
160170 // Check that the operator exists and has configured an allocation delay
161171 uint32 operatorAllocationDelay;
@@ -166,15 +176,15 @@ contract AllocationManager is
166176 }
167177
168178 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 );
170180
171181 // Check that the operator set exists and get the operator's registration status
172182 // Operators do not need to be registered for an operator set in order to allocate
173183 // slashable magnitude to the set. In fact, it is expected that operators will
174184 // allocate magnitude before registering, as AVS's will likely only accept
175185 // registrations from operators that are already slashable.
176186 OperatorSet memory operatorSet = params[i].operatorSet;
177- require (_operatorSets[ operatorSet.avs]. contains (operatorSet.id), InvalidOperatorSet () );
187+ _checkIsOperatorSet ( operatorSet);
178188
179189 bool _isOperatorSlashable = isOperatorSlashable (operator, operatorSet);
180190
@@ -246,8 +256,7 @@ contract AllocationManager is
246256 IStrategy[] calldata strategies ,
247257 uint16 [] calldata numToClear
248258 ) external onlyWhenNotPaused (PAUSED_MODIFY_ALLOCATIONS) {
249- require (strategies.length == numToClear.length , InputArrayLengthMismatch ());
250-
259+ _checkArrayLengthsMatch (strategies.length , numToClear.length );
251260 for (uint256 i = 0 ; i < strategies.length ; ++ i) {
252261 _clearDeallocationQueue ({operator: operator, strategy: strategies[i], numToClear: numToClear[i]});
253262 }
@@ -258,13 +267,13 @@ contract AllocationManager is
258267 address operator ,
259268 RegisterParams calldata params
260269 ) 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);
263272
264273 for (uint256 i = 0 ; i < params.operatorSetIds.length ; i++ ) {
265274 // Check the operator set exists and the operator is not currently registered to it
266275 OperatorSet memory operatorSet = OperatorSet (params.avs, params.operatorSetIds[i]);
267- require (_operatorSets[ operatorSet.avs]. contains (operatorSet.id), InvalidOperatorSet () );
276+ _checkIsOperatorSet ( operatorSet);
268277 require (! isOperatorSlashable (operator, operatorSet), AlreadyMemberOfSet ());
269278
270279 // Add operator to operator set
@@ -285,12 +294,12 @@ contract AllocationManager is
285294 DeregisterParams calldata params
286295 ) external onlyWhenNotPaused (PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION) {
287296 // 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 ());
289298
290299 for (uint256 i = 0 ; i < params.operatorSetIds.length ; i++ ) {
291300 // Check the operator set exists and the operator is registered to it
292301 OperatorSet memory operatorSet = OperatorSet (params.avs, params.operatorSetIds[i]);
293- require (_operatorSets[params.avs]. contains ( operatorSet.id), InvalidOperatorSet () );
302+ _checkIsOperatorSet ( operatorSet);
294303 require (registrationStatus[params.operator][operatorSet.key ()].registered, NotMemberOfSet ());
295304
296305 // Remove operator from operator set
@@ -313,8 +322,8 @@ contract AllocationManager is
313322 /// @inheritdoc IAllocationManager
314323 function setAllocationDelay (address operator , uint32 delay ) external {
315324 if (msg .sender != address (delegation)) {
316- require ( _checkCanCall (operator), InvalidCaller () );
317- require (delegation. isOperator ( operator), InvalidOperator () );
325+ _checkCanCall (operator);
326+ _checkIsOperator ( operator);
318327 }
319328 _setAllocationDelay (operator, delay);
320329 }
@@ -330,31 +339,28 @@ contract AllocationManager is
330339
331340 /// @inheritdoc IAllocationManager
332341 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 ;
337343 emit AVSMetadataURIUpdated (avs, metadataURI);
338344 }
339345
340346 /// @inheritdoc IAllocationManager
341347 function createOperatorSets (address avs , CreateSetParams[] calldata params ) external checkCanCall (avs) {
342- // Check that the AVS exists and has registered metadata
343348 require (_avsRegisteredMetadata[avs], NonexistentAVSMetadata ());
344-
345349 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+ }
351353
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]);
358364 }
359365 }
360366
@@ -365,10 +371,8 @@ contract AllocationManager is
365371 IStrategy[] calldata strategies
366372 ) external checkCanCall (avs) {
367373 OperatorSet memory operatorSet = OperatorSet (avs, operatorSetId);
374+ _checkIsOperatorSet (operatorSet);
368375 bytes32 operatorSetKey = operatorSet.key ();
369-
370- require (_operatorSets[avs].contains (operatorSet.id), InvalidOperatorSet ());
371-
372376 for (uint256 i = 0 ; i < strategies.length ; i++ ) {
373377 require (_operatorSetStrategies[operatorSetKey].add (address (strategies[i])), StrategyAlreadyInOperatorSet ());
374378 emit StrategyAddedToOperatorSet (operatorSet, strategies[i]);
@@ -382,8 +386,7 @@ contract AllocationManager is
382386 IStrategy[] calldata strategies
383387 ) external checkCanCall (avs) {
384388 OperatorSet memory operatorSet = OperatorSet (avs, operatorSetId);
385- require (_operatorSets[avs].contains (operatorSet.id), InvalidOperatorSet ());
386-
389+ _checkIsOperatorSet (operatorSet);
387390 bytes32 operatorSetKey = operatorSet.key ();
388391 for (uint256 i = 0 ; i < strategies.length ; i++ ) {
389392 require (_operatorSetStrategies[operatorSetKey].remove (address (strategies[i])), StrategyNotInOperatorSet ());
@@ -397,6 +400,41 @@ contract AllocationManager is
397400 *
398401 */
399402
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+
400438 /**
401439 * @dev Clear one or more pending deallocations to a strategy's allocated magnitude
402440 * @param operator the operator whose pending deallocations will be cleared
@@ -605,6 +643,25 @@ contract AllocationManager is
605643 return uint256 (int256 (int128 (uint128 (a)) + b)).toUint64 ();
606644 }
607645
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+
608665 /**
609666 *
610667 * VIEW FUNCTIONS
@@ -905,4 +962,27 @@ contract AllocationManager is
905962 // less than or equal to
906963 return status.registered || block .number <= status.slashableUntil;
907964 }
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+ }
908988}
0 commit comments