Skip to content

Commit

Permalink
feat: constrain maximum strategies per operator set (#935)
Browse files Browse the repository at this point in the history
* feat: add `MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH`

- and constrain opsets to contain no more than `MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH` strategies

* refactor: review changes
  • Loading branch information
0xClandestine authored Dec 6, 2024
1 parent f819336 commit 40ba7e7
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 2 deletions.
11 changes: 10 additions & 1 deletion src/contracts/core/AllocationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ contract AllocationManager is
/// @inheritdoc IAllocationManager
function createOperatorSets(address avs, CreateSetParams[] calldata params) external checkCanCall(avs) {
for (uint256 i = 0; i < params.length; i++) {
require(params[i].strategies.length <= MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH, MaxStrategiesExceeded());

OperatorSet memory operatorSet = OperatorSet(avs, params[i].operatorSetId);

// Create the operator set, ensuring it does not already exist
Expand All @@ -315,6 +317,7 @@ contract AllocationManager is

// Add strategies to the operator set
bytes32 operatorSetKey = operatorSet.key();

for (uint256 j = 0; j < params[i].strategies.length; j++) {
_operatorSetStrategies[operatorSetKey].add(address(params[i].strategies[j]));
emit StrategyAddedToOperatorSet(operatorSet, params[i].strategies[j]);
Expand All @@ -329,9 +332,15 @@ contract AllocationManager is
IStrategy[] calldata strategies
) external checkCanCall(avs) {
OperatorSet memory operatorSet = OperatorSet(avs, operatorSetId);
bytes32 operatorSetKey = operatorSet.key();

require(
_operatorSetStrategies[operatorSetKey].length() + strategies.length <= MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH,
MaxStrategiesExceeded()
);

require(_operatorSets[avs].contains(operatorSet.id), InvalidOperatorSet());

bytes32 operatorSetKey = operatorSet.key();
for (uint256 i = 0; i < strategies.length; i++) {
require(_operatorSetStrategies[operatorSetKey].add(address(strategies[i])), StrategyAlreadyInOperatorSet());
emit StrategyAddedToOperatorSet(operatorSet, strategies[i]);
Expand Down
4 changes: 4 additions & 0 deletions src/contracts/core/AllocationManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ abstract contract AllocationManagerStorage is IAllocationManager {
/// @dev Index for flag that pauses operator register/deregister to operator sets when set.
uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 2;

/// @dev Returns the maximum number of strategies an operator set can support.
/// NOTE: 32 LST strategies + 1 beacon chain ETH strategy = 33 total strategies.
uint8 internal constant MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH = 33;

// Immutables

/// @notice The DelegationManager contract for EigenLayer
Expand Down
2 changes: 2 additions & 0 deletions src/contracts/interfaces/IAllocationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface IAllocationManagerErrors {
error InputArrayLengthMismatch();
/// @dev Thrown when calling a view function that requires a valid block number.
error InvalidBlockNumber();
/// @dev Thrown when creating an operator set with more than max strategies.
error MaxStrategiesExceeded();

/// Caller

Expand Down
41 changes: 40 additions & 1 deletion src/test/unit/AllocationManagerUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag
uint256 internal constant FUZZ_MAX_STRATS = 8;
uint256 internal constant FUZZ_MAX_OP_SETS = 8;

uint8 internal constant MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH = 33;

uint8 internal constant PAUSED_MODIFY_ALLOCATIONS = 0;
uint8 internal constant PAUSED_OPERATOR_SLASHING = 1;
uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 2;
Expand Down Expand Up @@ -3088,6 +3090,8 @@ contract AllocationManagerUnitTests_deregisterFromOperatorSets is AllocationMana
}

contract AllocationManagerUnitTests_addStrategiesToOperatorSet is AllocationManagerUnitTests {
using SingleItemArrayLib for *;

function test_addStrategiesToOperatorSet_InvalidOperatorSet() public {
cheats.prank(defaultAVS);
cheats.expectRevert(InvalidOperatorSet.selector);
Expand All @@ -3100,6 +3104,29 @@ contract AllocationManagerUnitTests_addStrategiesToOperatorSet is AllocationMana
allocationManager.addStrategiesToOperatorSet(defaultAVS, defaultOperatorSet.id, defaultStrategies);
}

function test_addStrategiesToOperatorSet_MaxStrategiesExceeded() public {
cheats.startPrank(defaultAVS);
cheats.expectRevert(MaxStrategiesExceeded.selector);
allocationManager.addStrategiesToOperatorSet(
defaultAVS, defaultOperatorSet.id, new IStrategy[](MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH + 1)
);

for (uint256 i; i < MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH - 1; ++i) {
allocationManager.addStrategiesToOperatorSet(
defaultAVS,
defaultOperatorSet.id,
IStrategy(cheats.randomAddress()).toArray()
);
}

cheats.expectRevert(MaxStrategiesExceeded.selector);
allocationManager.addStrategiesToOperatorSet(
defaultAVS,
defaultOperatorSet.id,
IStrategy(cheats.randomAddress()).toArray()
);
}

function testFuzz_addStrategiesToOperatorSet_Correctness(
Randomness r
) public rand(r) {
Expand Down Expand Up @@ -3172,12 +3199,24 @@ contract AllocationManagerUnitTests_removeStrategiesFromOperatorSet is Allocatio
contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitTests {
using SingleItemArrayLib for *;

function test_createOperatorSets_InvalidOperatorSet() public {
function testRevert_createOperatorSets_InvalidOperatorSet() public {
cheats.prank(defaultAVS);
cheats.expectRevert(InvalidOperatorSet.selector);
allocationManager.createOperatorSets(defaultAVS, CreateSetParams(defaultOperatorSet.id, defaultStrategies).toArray());
}

function testRevert_createOperatorSets_MaxStrategiesExceeded() public {
cheats.prank(defaultAVS);
cheats.expectRevert(MaxStrategiesExceeded.selector);
allocationManager.createOperatorSets(
defaultAVS,
CreateSetParams(
defaultOperatorSet.id,
new IStrategy[](MAX_OPERATOR_SET_STRATEGY_LIST_LENGTH + 1)
).toArray()
);
}

function testFuzz_createOperatorSets_Correctness(
Randomness r
) public rand(r) {
Expand Down

0 comments on commit 40ba7e7

Please sign in to comment.