From d93f1c032c1482ed43e3171d955b3d0e9a425103 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:56:30 -0500 Subject: [PATCH 01/11] test(wip): todos --- lib/forge-std | 1 - src/contracts/strategies/EigenStrategy.sol | 2 +- src/test/unit/AllocationManagerUnit.t.sol | 191 ++++++++++++++------- src/test/unit/DelegationUnit.t.sol | 4 +- src/test/utils/Random.sol | 119 ++++++++++++- 5 files changed, 249 insertions(+), 68 deletions(-) delete mode 160000 lib/forge-std diff --git a/lib/forge-std b/lib/forge-std deleted file mode 160000 index da591f56d..000000000 --- a/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da591f56d8884c5824c0c1b3103fbcfd81123c4c diff --git a/src/contracts/strategies/EigenStrategy.sol b/src/contracts/strategies/EigenStrategy.sol index b3bacef3b..f73bccf30 100644 --- a/src/contracts/strategies/EigenStrategy.sol +++ b/src/contracts/strategies/EigenStrategy.sol @@ -40,7 +40,7 @@ contract EigenStrategy is StrategyBase { IPauserRegistry _pauserRegistry ) StrategyBase(_strategyManager, _pauserRegistry) {} - function initialize(IEigen _EIGEN, IERC20 _bEIGEN, IPauserRegistry _pauserRegistry) public virtual initializer { + function initialize(IEigen _EIGEN, IERC20 _bEIGEN) public virtual initializer { EIGEN = _EIGEN; _initializeStrategyBase(_bEIGEN); } diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index 8492d7fee..faa338928 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -10,6 +10,11 @@ import "src/test/mocks/MockAVSRegistrar.sol"; contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManagerErrors, IAllocationManagerEvents { using SingleItemArrayLib for *; + /// NOTE: Raising these values directly increases cpu time for tests. + uint256 internal constant FUZZ_MAX_ALLOCATIONS = 8; + uint256 internal constant FUZZ_MAX_STRATS = 8; + uint256 internal constant FUZZ_MAX_OP_SETS = 8; + uint8 internal constant PAUSED_MODIFY_ALLOCATIONS = 0; uint8 internal constant PAUSED_OPERATOR_SLASHING = 1; uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 2; @@ -106,9 +111,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag ) ), address(eigenLayerProxyAdmin), - abi.encodeWithSelector( - AllocationManager.initialize.selector, _initialOwner, _initialPausedStatus - ) + abi.encodeWithSelector(AllocationManager.initialize.selector, _initialOwner, _initialPausedStatus) ) ) ); @@ -1028,8 +1031,8 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests // // Allocate 40% to firstOperatorSet, 40% to secondOperatorSet // AllocateParams[] memory allocateParams = new AllocateParams[](2); - // allocateParams[0] = _newAllocateParams_SingleMockStrategy(OperatorSet(defaultAVS, 1), magnitudeToAllocate)[0]; - // allocateParams[1] = _newAllocateParams_SingleMockStrategy(OperatorSet(defaultAVS, 2), magnitudeToAllocate)[0]; + // allocateParams[0] = _newAllocateParams(OperatorSet(defaultAVS, 1), magnitudeToAllocate)[0]; + // allocateParams[1] = _newAllocateParams(OperatorSet(defaultAVS, 2), magnitudeToAllocate)[0]; // cheats.prank(defaultOperator); // allocationManager.modifyAllocations(allocateParams); // cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); @@ -1182,8 +1185,8 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests Randomness r ) public rand(r) { // Bound allocation and deallocation - uint64 firstMod = uint64(r.Uint256(3, WAD)); - uint64 secondMod = uint64(r.Uint256(1, firstMod - 2)); + uint64 firstMod = r.Uint64(3, WAD); + uint64 secondMod = r.Uint64(1, firstMod - 2); // TODO: remove these assumptions around even numbers if (firstMod % 2 != 0) { @@ -1273,9 +1276,6 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe using SingleItemArrayLib for *; using OperatorSetLib for *; - /// ----------------------------------------------------------------------- - /// modifyAllocations() - /// ----------------------------------------------------------------------- function test_revert_paused() public { allocationManager.pause(2 ** PAUSED_MODIFY_ALLOCATIONS); cheats.expectRevert(IPausable.CurrentlyPaused.selector); @@ -1521,10 +1521,8 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe function testFuzz_allocateMultipleTimes( Randomness r ) public rand(r) { - // Assumptions - uint64 firstAlloc = uint64(r.Uint256(1, type(uint64).max)); - uint64 secondAlloc = uint64(r.Uint256(0, WAD)); - cheats.assume(firstAlloc < secondAlloc); + uint64 firstAlloc = r.Uint64(1, WAD - 1); + uint64 secondAlloc = r.Uint64(firstAlloc + 1, WAD); // Check that the operator has no allocated sets/strats before allocation OperatorSet[] memory allocatedSets = allocationManager.getAllocatedSets(defaultOperator); @@ -1657,8 +1655,8 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe Randomness r ) public rand(r) { // Bound allocation and deallocation - uint64 firstMod = uint64(r.Uint256(1, WAD)); - uint64 secondMod = uint64(r.Uint256(0, firstMod - 1)); + uint64 firstMod = r.Uint64(1, WAD); + uint64 secondMod = r.Uint64(0, firstMod - 1); // Allocate magnitude to default registered set AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstMod); @@ -1972,9 +1970,85 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe ); } - function testFuzz_allocate_WithDeallocationQueue( + /// @dev Set allocation delay > ALLOCATION_CONFIGURATION_DELAY, allocate, + /// set allocation delay to < ALLOCATION_CONFIGURATION_DELAY, allocate again + /// once new delay is set. + /// + /// NOTE: Should be able to allocate faster than `ALLOCATION_CONFIGURATION_DELAY`. + function testFuzz_modifyAllocations_ShouldBeAbleToAllocateSoonerThanLastDelay( Randomness r - ) public rand(r) {} + ) public rand(r) { + uint32 firstDelay = r.Uint32(ALLOCATION_CONFIGURATION_DELAY, type(uint24).max); + uint32 secondDelay = r.Uint32(1, ALLOCATION_CONFIGURATION_DELAY - 1); + uint64 half = 0.5 ether; + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(CreateSetParams(1, defaultStrategies).toArray()); + + cheats.startPrank(defaultOperator); + + allocationManager.setAllocationDelay(firstDelay); + allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, half)); + + allocationManager.setAllocationDelay(secondDelay); + cheats.roll(block.number + secondDelay); + allocationManager.modifyAllocations(_newAllocateParams(OperatorSet(defaultAVS, 1), half)); + + cheats.stopPrank(); + } + + function testFuzz_modifyAllocations_MultipleSetsAndStrats( + Randomness r + ) public rand(r) { + uint256 numAllocations = r.Uint256(2, FUZZ_MAX_ALLOCATIONS); + uint256 numStrats = r.Uint256(2, FUZZ_MAX_STRATS); + + AllocateParams[] memory allocateParams = r.allocateParams(defaultAVS, numAllocations, numStrats); + AllocateParams[] memory deallocateParams = r.deallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(createSetParams); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + + for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + Allocation memory allocation = + allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j]); + assertEq(allocation.currentMagnitude, 0, "currentMagnitude not updated"); + assertEq(allocation.pendingDiff, int64(allocateParams[i].newMagnitudes[j]), "pendingMagnitude not updated"); + assertEq(allocation.effectBlock, block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY, "effectBlock not updated"); + } + } + + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + Allocation memory allocation = + allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j]); + assertEq(allocation.currentMagnitude, allocateParams[i].newMagnitudes[j], "currentMagnitude not updated"); + assertEq(allocation.pendingDiff, 0, "pendingMagnitude not updated"); + assertEq(allocation.effectBlock, 0, "effectBlock not updated"); + } + } + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(deallocateParams); + + // Deallocations are immediate if the operator's allocation is not slashable. + for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + Allocation memory allocation = + allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j]); + assertEq(allocation.currentMagnitude, deallocateParams[i].newMagnitudes[j], "currentMagnitude not updated"); + assertEq(allocation.pendingDiff, 0, "pendingMagnitude not updated"); + assertEq(allocation.effectBlock, 0, "effectBlock not updated"); + } + } + } } contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerUnitTests { @@ -2231,7 +2305,7 @@ contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitT function testFuzz_setDelay( Randomness r ) public rand(r) { - uint32 delay = uint32(r.Uint256(0, type(uint32).max)); + uint32 delay = r.Uint32(0, type(uint32).max); // Set delay cheats.expectEmit(true, true, true, true, address(allocationManager)); @@ -2256,9 +2330,8 @@ contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitT function test_fuzz_setDelay_multipleTimesWithinConfigurationDelay( Randomness r ) public rand(r) { - uint32 firstDelay = uint32(r.Uint256(0, type(uint32).max)); - uint32 secondDelay = uint32(r.Uint256(0, type(uint32).max)); - cheats.assume(firstDelay != secondDelay); + uint32 firstDelay = r.Uint32(1, type(uint32).max); + uint32 secondDelay = r.Uint32(1, type(uint32).max); // Set delay cheats.prank(operatorToSet); @@ -2291,9 +2364,8 @@ contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitT function testFuzz_multipleDelays( Randomness r ) public rand(r) { - uint32 firstDelay = uint32(r.Uint256(1, type(uint32).max)); - uint32 secondDelay = uint32(r.Uint256(1, type(uint32).max)); - cheats.assume(firstDelay != secondDelay); + uint32 firstDelay = r.Uint32(1, type(uint32).max); + uint32 secondDelay = r.Uint32(1, type(uint32).max); // Set delay cheats.prank(operatorToSet); @@ -2323,7 +2395,7 @@ contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitT function testFuzz_setDelay_DMCaller( Randomness r ) public rand(r) { - uint32 delay = uint32(r.Uint256(1, type(uint32).max)); + uint32 delay = r.Uint32(1, type(uint32).max); cheats.prank(address(delegationManagerMock)); allocationManager.setAllocationDelay(operatorToSet, delay); @@ -2371,7 +2443,7 @@ contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManager Randomness r ) public rand(r) { address operator = r.Address(); - uint256 numOpSets = r.Uint256(1, 32); + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); uint32[] memory operatorSetIds = new uint32[](numOpSets); CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); @@ -2398,11 +2470,12 @@ contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManager cheats.prank(operator); allocationManager.registerForOperatorSets(RegisterParams(defaultAVS, operatorSetIds, "")); - require(allocationManager.getRegisteredSets(operator).length == numOpSets, "should be registered for all sets"); + assertEq(allocationManager.getRegisteredSets(operator).length, numOpSets, "should be registered for all sets"); for (uint256 k; k < numOpSets; ++k) { - require( - allocationManager.getMembers(OperatorSet(defaultAVS, operatorSetIds[k]))[0] == operator, + assertEq( + allocationManager.getMembers(OperatorSet(defaultAVS, operatorSetIds[k]))[0], + operator, "should be member of set" ); } @@ -2447,7 +2520,7 @@ contract AllocationManagerUnitTests_deregisterFromOperatorSets is AllocationMana function testFuzz_deregisterFromOperatorSets_Correctness( Randomness r ) public rand(r) { - uint256 numOpSets = r.Uint256(1, 32); + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); uint32[] memory operatorSetIds = new uint32[](numOpSets); CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); @@ -2478,11 +2551,12 @@ contract AllocationManagerUnitTests_deregisterFromOperatorSets is AllocationMana cheats.prank(operator); allocationManager.deregisterFromOperatorSets(DeregisterParams(operator, defaultAVS, operatorSetIds)); - require(allocationManager.getRegisteredSets(operator).length == 0, "should not be registered for any sets"); + assertEq(allocationManager.getRegisteredSets(operator).length, 0, "should not be registered for any sets"); for (uint256 k; k < numOpSets; ++k) { - require( - allocationManager.getMemberCount(OperatorSet(defaultAVS, operatorSetIds[k])) == 0, + assertEq( + allocationManager.getMemberCount(OperatorSet(defaultAVS, operatorSetIds[k])), + 0, "should not be member of set" ); } @@ -2505,7 +2579,7 @@ contract AllocationManagerUnitTests_addStrategiesToOperatorSet is AllocationMana function testFuzz_addStrategiesToOperatorSet_Correctness( Randomness r ) public rand(r) { - uint256 numStrategies = r.Uint256(1, 32); + uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); IStrategy[] memory strategies = new IStrategy[](numStrategies); @@ -2521,7 +2595,7 @@ contract AllocationManagerUnitTests_addStrategiesToOperatorSet is AllocationMana IStrategy[] memory strategiesInSet = allocationManager.getStrategiesInOperatorSet(defaultOperatorSet); for (uint256 j; j < numStrategies; ++j) { - require(strategiesInSet[j + 1] == strategies[j], "should be strat of set"); + assertTrue(strategiesInSet[j + 1] == strategies[j], "should be strat of set"); } } } @@ -2546,7 +2620,7 @@ contract AllocationManagerUnitTests_removeStrategiesFromOperatorSet is Allocatio function testFuzz_removeStrategiesFromOperatorSet_Correctness( Randomness r ) public rand(r) { - uint256 numStrategies = r.Uint256(1, 32); + uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); IStrategy[] memory strategies = r.strategyArray(numStrategies); cheats.prank(defaultAVS); @@ -2557,16 +2631,16 @@ contract AllocationManagerUnitTests_removeStrategiesFromOperatorSet is Allocatio emit StrategyRemovedFromOperatorSet(defaultOperatorSet, strategies[i]); } - require( - allocationManager.getStrategiesInOperatorSet(defaultOperatorSet).length == numStrategies + 1, "sanity check" + assertEq( + allocationManager.getStrategiesInOperatorSet(defaultOperatorSet).length, numStrategies + 1, "sanity check" ); cheats.prank(defaultAVS); allocationManager.removeStrategiesFromOperatorSet(defaultOperatorSet.id, strategies); // The orginal strategy should still be in the operator set. - require( - allocationManager.getStrategiesInOperatorSet(defaultOperatorSet).length == 1, "should not be strat of set" + assertEq( + allocationManager.getStrategiesInOperatorSet(defaultOperatorSet).length, 1, "should not be strat of set" ); } } @@ -2584,8 +2658,8 @@ contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitT Randomness r ) public rand(r) { address avs = r.Address(); - uint256 numOpSets = r.Uint256(1, 32); - uint256 numStrategies = r.Uint256(1, 32); + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); + uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); @@ -2607,11 +2681,11 @@ contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitT for (uint256 k; k < numOpSets; ++k) { OperatorSet memory opSet = OperatorSet(avs, createSetParams[k].operatorSetId); - require(allocationManager.isOperatorSet(opSet), "should be operator set"); + assertTrue(allocationManager.isOperatorSet(opSet), "should be operator set"); IStrategy[] memory strategiesInSet = allocationManager.getStrategiesInOperatorSet(opSet); - require(strategiesInSet.length == numStrategies, "strategiesInSet length should be numStrategies"); + assertEq(strategiesInSet.length, numStrategies, "strategiesInSet length should be numStrategies"); for (uint256 l; l < numStrategies; ++l) { - require( + assertTrue( allocationManager.getStrategiesInOperatorSet(opSet)[l] == createSetParams[k].strategies[l], "should be strat of set" ); @@ -2621,22 +2695,17 @@ contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitT } contract AllocationManagerUnitTests_setAVSRegistrar is AllocationManagerUnitTests { - function test_setAVSRegistrar_Correctness() public { - IAVSRegistrar avsRegistrar = IAVSRegistrar(random().Address()); + function testFuzz_setAVSRegistrar_Correctness( + Randomness r + ) public rand(r) { + address avs = r.Address(); + IAVSRegistrar avsRegistrar = IAVSRegistrar(r.Address()); + cheats.expectEmit(true, false, false, false, address(allocationManager)); - emit AVSRegistrarSet(defaultAVS, avsRegistrar); - cheats.prank(defaultAVS); + emit AVSRegistrarSet(avs, avsRegistrar); + + cheats.prank(avs); allocationManager.setAVSRegistrar(avsRegistrar); - assertEq(address(avsRegistrar), address(allocationManager.getAVSRegistrar(defaultAVS)), "should be set"); + assertTrue(avsRegistrar == allocationManager.getAVSRegistrar(avs), "should be set"); } } - -/** - * @notice TODO Lifecycle tests - These tests combine multiple functionalities of the AllocationManager - * 1. Set allocation delay > 21 days (configuration), Allocate, modify allocation delay to < 21 days, try to allocate again once new delay is set (should be able to allocate faster than 21 deays) - * 2. Allocate across multiple strategies and multiple operatorSets - * 3. lifecycle fuzz test allocating/deallocating across multiple opSets/strategies - * 4. HIGH PRIO - add uint16.max allocateParams/deallocateParams and then clear them - * 5. Correctness of slashable magnitudes - * 6. HIGH PRIO - get gas costs of `getSlashableMagnitudes` - */ diff --git a/src/test/unit/DelegationUnit.t.sol b/src/test/unit/DelegationUnit.t.sol index 753567df9..80f3f3ff9 100644 --- a/src/test/unit/DelegationUnit.t.sol +++ b/src/test/unit/DelegationUnit.t.sol @@ -2777,7 +2777,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // Format queued withdrawal ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + , IDelegationManagerTypes.Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ @@ -3221,7 +3221,7 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); uint256 delegatedSharesBefore = delegationManager.operatorShares(defaultOperator, strategies[0]); - (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + // (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); // queueWithdrawals cheats.expectEmit(true, true, true, true, address(delegationManager)); diff --git a/src/test/utils/Random.sol b/src/test/utils/Random.sol index 3d2e3e152..76a8b537c 100644 --- a/src/test/utils/Random.sol +++ b/src/test/utils/Random.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; +import "src/contracts/interfaces/IAllocationManager.sol"; import "src/contracts/interfaces/IStrategy.sol"; import "src/contracts/libraries/OperatorSetLib.sol"; @@ -13,10 +14,10 @@ library Random { /// Constants /// ----------------------------------------------------------------------- - // Equivalent to: `uint256(keccak256("RANDOMNESS.SEED"))`. + /// @dev Equivalent to: `uint256(keccak256("RANDOMNESS.SEED"))`. uint256 constant SEED = 0x93bfe7cafd9427243dc4fe8c6e706851eb6696ba8e48960dd74ecc96544938ce; - /// Equivalent to: `uint256(keccak256("RANDOMNESS.SEED"))`. + /// @dev Equivalent to: `uint256(keccak256("RANDOMNESS.SLOT"))`. uint256 constant SLOT = 0xd0660badbab446a974e6a19901c78a2ad88d7e4f1710b85e1cfc0878477344fd; /// ----------------------------------------------------------------------- @@ -59,6 +60,16 @@ library Random { return r.shuffle().unwrap(); } + function Uint128(Randomness r, uint128 min, uint128 max) internal returns (uint128) { + return uint128(Uint256(r, min, max)); + } + + function Uint128( + Randomness r + ) internal returns (uint128) { + return uint128(Uint256(r)); + } + function Uint64(Randomness r, uint64 min, uint64 max) internal returns (uint64) { return uint64(Uint256(r, min, max)); } @@ -92,7 +103,7 @@ library Random { } /// ----------------------------------------------------------------------- - /// EigenLayer Types + /// General Types /// ----------------------------------------------------------------------- function strategyArray(Randomness r, uint256 len) internal returns (IStrategy[] memory strategies) { @@ -113,6 +124,108 @@ library Random { } } + /// ----------------------------------------------------------------------- + /// `AllocationManager` Types + /// ----------------------------------------------------------------------- + + /// @dev Usage: `r.createSetParams(r, numOpSets, numStrats)`. + function createSetParams( + Randomness r, + uint256 numOpSets, + uint256 numStrats + ) internal returns (IAllocationManagerTypes.CreateSetParams[] memory params) { + params = new IAllocationManagerTypes.CreateSetParams[](numOpSets); + for (uint256 i; i < numOpSets; ++i) { + params[i].operatorSetId = r.Uint32(1, type(uint32).max); + params[i].strategies = r.strategyArray(numStrats); + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(r.createSetParams(allocateParams)); + /// ``` + function createSetParams( + Randomness, + IAllocationManagerTypes.AllocateParams[] memory allocateParams + ) internal pure returns (IAllocationManagerTypes.CreateSetParams[] memory params) { + params = new IAllocationManagerTypes.CreateSetParams[](allocateParams.length); + for (uint256 i; i < allocateParams.length; ++i) { + params[i] = IAllocationManagerTypes.CreateSetParams( + allocateParams[i].operatorSet.id, allocateParams[i].strategies + ); + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + /// + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(createSetParams); + /// + /// cheats.prank(operator); + /// allocationManager.modifyAllocations(allocateParams); + /// ``` + function allocateParams( + Randomness r, + address avs, + uint256 numAllocations, + uint256 numStrats + ) internal returns (IAllocationManagerTypes.AllocateParams[] memory allocateParams) { + allocateParams = new IAllocationManagerTypes.AllocateParams[](numAllocations); + + // TODO: Randomize magnitudes such that they sum to 1e18 (100%). + uint64 magnitudePerSet = uint64(WAD / numStrats); + + for (uint256 i; i < numAllocations; ++i) { + allocateParams[i].operatorSet = OperatorSet(avs, r.Uint32()); + allocateParams[i].strategies = r.strategyArray(numStrats); + allocateParams[i].newMagnitudes = new uint64[](numStrats); + + for (uint256 j; j < numStrats; ++j) { + allocateParams[i].newMagnitudes[j] = magnitudePerSet; + } + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// AllocateParams[] memory deallocateParams = r.deallocateParams(allocateParams); + /// CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + /// + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(createSetParams); + /// + /// cheats.prank(operator); + /// allocationManager.modifyAllocations(allocateParams); + /// + /// cheats.prank(operator) + /// allocationManager.modifyAllocations(deallocateParams); + /// ``` + function deallocateParams( + Randomness r, + IAllocationManagerTypes.AllocateParams[] memory allocateParams + ) internal returns (IAllocationManagerTypes.AllocateParams[] memory deallocateParams) { + uint256 numDeallocations = allocateParams.length; + + deallocateParams = new IAllocationManagerTypes.AllocateParams[](numDeallocations); + + for (uint256 i; i < numDeallocations; ++i) { + deallocateParams[i].operatorSet = allocateParams[i].operatorSet; + deallocateParams[i].strategies = allocateParams[i].strategies; + + deallocateParams[i].newMagnitudes = new uint64[](allocateParams[i].strategies.length); + for (uint256 j; j < allocateParams[i].strategies.length; ++j) { + deallocateParams[i].newMagnitudes[j] = r.Uint64(0, allocateParams[i].newMagnitudes[j] - 1); + } + } + } + /// ----------------------------------------------------------------------- /// Helpers /// ----------------------------------------------------------------------- From dd12720ed6ba435cc1c6c83de013338bd2dce873 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:56:57 -0500 Subject: [PATCH 02/11] test: remove unused utils --- src/test/utils/BeaconChainProofsWrapper.sol | 41 ------------------ src/test/utils/Operators.sol | 48 --------------------- src/test/utils/Owners.sol | 47 -------------------- src/test/utils/SignatureCompaction.sol | 29 ------------- src/test/utils/Utils.sol | 23 ---------- 5 files changed, 188 deletions(-) delete mode 100644 src/test/utils/BeaconChainProofsWrapper.sol delete mode 100644 src/test/utils/Operators.sol delete mode 100644 src/test/utils/Owners.sol delete mode 100644 src/test/utils/SignatureCompaction.sol delete mode 100644 src/test/utils/Utils.sol diff --git a/src/test/utils/BeaconChainProofsWrapper.sol b/src/test/utils/BeaconChainProofsWrapper.sol deleted file mode 100644 index d8e4aff10..000000000 --- a/src/test/utils/BeaconChainProofsWrapper.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "src/contracts/libraries/BeaconChainProofs.sol"; - -/// @notice This contract is used to test offchain proof generation -contract BeaconChainProofsWrapper { - - function verifyStateRoot( - bytes32 beaconBlockRoot, - BeaconChainProofs.StateRootProof calldata proof - ) external view { - BeaconChainProofs.verifyStateRoot(beaconBlockRoot, proof); - } - - function verifyValidatorFields( - bytes32 beaconStateRoot, - bytes32[] calldata validatorFields, - bytes calldata validatorFieldsProof, - uint40 validatorIndex - ) external view { - BeaconChainProofs.verifyValidatorFields(beaconStateRoot, validatorFields, validatorFieldsProof, validatorIndex); - } - - function verifyBalanceContainer( - bytes32 beaconBlockRoot, - BeaconChainProofs.BalanceContainerProof calldata proof - ) external view { - BeaconChainProofs.verifyBalanceContainer(beaconBlockRoot, proof); - } - - function verifyValidatorBalance( - bytes32 balanceContainerRoot, - uint40 validatorIndex, - BeaconChainProofs.BalanceProof calldata proof - ) external view { - BeaconChainProofs.verifyValidatorBalance(balanceContainerRoot, validatorIndex, proof); - } - - -} \ No newline at end of file diff --git a/src/test/utils/Operators.sol b/src/test/utils/Operators.sol deleted file mode 100644 index 1bc8acd50..000000000 --- a/src/test/utils/Operators.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "forge-std/Test.sol"; -import "forge-std/Script.sol"; -import "forge-std/StdJson.sol"; - -contract Operators is Test { - string internal operatorConfigJson; - - constructor() { - operatorConfigJson = vm.readFile("./src/test/test-data/operators.json"); - } - - function operatorPrefix(uint256 index) public pure returns(string memory) { - return string.concat(".operators[", string.concat(vm.toString(index), "].")); - } - - function getNumOperators() public view returns(uint256) { - return stdJson.readUint(operatorConfigJson, ".numOperators"); - } - - function getOperatorAddress(uint256 index) public view returns (address) { - return stdJson.readAddress(operatorConfigJson, string.concat(operatorPrefix(index), "Address")); - } - - function getOperatorSecretKey(uint256 index) public view returns (uint256) { - return readUint(operatorConfigJson, index, "SecretKey"); - } - - function readUint(string memory json, uint256 index, string memory key) public pure returns (uint256) { - return stringToUint(stdJson.readString(json, string.concat(operatorPrefix(index), key))); - } - - function stringToUint(string memory s) public pure returns (uint256) { - bytes memory b = bytes(s); - uint256 result = 0; - for (uint256 i = 0; i < b.length; i++) { - if (uint256(uint8(b[i])) >= 48 && uint256(uint8(b[i])) <= 57) { - result = result * 10 + (uint256(uint8(b[i])) - 48); - } - } - return result; - } - function setOperatorJsonFilePath(string memory filepath) public { - operatorConfigJson = vm.readFile(filepath); - } -} diff --git a/src/test/utils/Owners.sol b/src/test/utils/Owners.sol deleted file mode 100644 index 6b55c70bf..000000000 --- a/src/test/utils/Owners.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "forge-std/Test.sol"; -import "forge-std/Script.sol"; -import "forge-std/StdJson.sol"; - -contract Owners is Test { - string internal ownersConfigJson; - address[] addresses; - - constructor() { - ownersConfigJson = vm.readFile("./src/test/test-data/owners.json"); - } - - function ownerPrefix(uint256 index) public pure returns(string memory) { - return string.concat(".owners[", string.concat(vm.toString(index), "].")); - } - - function getNumOperators() public view returns(uint256) { - return stdJson.readUint(ownersConfigJson, ".numOwners"); - } - - function getOwnerAddress(uint256 index) public view returns(address) { - return stdJson.readAddress(ownersConfigJson, string.concat(ownerPrefix(index), "Address")); - } - - function getOwnerAddresses() public returns(address[] memory) { - for (uint256 i = 0; i < getNumOperators(); i++) { - addresses.push(getOwnerAddress(i)); - } - return addresses; - } - - function getReputedOwnerAddresses() public returns(address[] memory) { - resetOwnersConfigJson("reputedOwners.json"); - for (uint256 i = 0; i < getNumOperators(); i++) { - addresses.push(getOwnerAddress(i)); - } - return addresses; - } - - function resetOwnersConfigJson(string memory newConfig) public { - ownersConfigJson = vm.readFile(newConfig); - } - -} diff --git a/src/test/utils/SignatureCompaction.sol b/src/test/utils/SignatureCompaction.sol deleted file mode 100644 index 0bb98a1c0..000000000 --- a/src/test/utils/SignatureCompaction.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -//small library for dealing with efficiently-packed signatures, where parameters v,r,s are packed into vs and r (64 bytes instead of 65) -library SignatureCompaction { - bytes32 internal constant HALF_CURVE_ORDER = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0; - - function ecrecoverPacked(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { - (address recovered, ECDSA.RecoverError err) = ECDSA.tryRecover(hash, r, vs); - require(err == ECDSA.RecoverError.NoError, "error in ecrecoverPacked"); - return recovered; - } - - function packSignature(bytes32 r, bytes32 s, uint8 v) internal pure returns (bytes32, bytes32) { - require(s <= HALF_CURVE_ORDER, "malleable signature, s too high"); - //v parity is a single bit, encoded as either v = 27 or v = 28 -- in order to recover the bit we subtract 27 - bytes32 vs = bytes32(uint256(bytes32(uint256(v) - 27) << 255) | uint256(s)); - return (r, vs); - } - - //same as above, except doesn't take 'r' as argument since it is unneeded - function packVS(bytes32 s, uint8 v) internal pure returns (bytes32) { - require(s <= HALF_CURVE_ORDER, "malleable signature, s too high"); - //v parity is a single bit, encoded as either v = 27 or v = 28 -- in order to recover the bit we subtract 27 - return bytes32(uint256(bytes32(uint256(v) - 27) << 255) | uint256(s)); - } -} diff --git a/src/test/utils/Utils.sol b/src/test/utils/Utils.sol deleted file mode 100644 index 505328983..000000000 --- a/src/test/utils/Utils.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.8.27; - -import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import "src/contracts/strategies/StrategyBase.sol"; - -contract Utils { - address constant dummyAdmin = address(uint160(uint256(keccak256("DummyAdmin")))); - - function deployNewStrategy(IERC20 token, IStrategyManager strategyManager, IPauserRegistry pauserRegistry, address admin) public returns (StrategyBase) { - StrategyBase newStrategy = new StrategyBase(strategyManager, pauserRegistry); - newStrategy = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(newStrategy), - address(admin), - "" - ) - ) - ); - newStrategy.initialize(token); - return newStrategy; - } -} From 4607c51f1c9dbd0f7dc1a86a9820e598a79e4b3c Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:57:25 -0500 Subject: [PATCH 03/11] feat: foundry `sparse_mode=true` --- foundry.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/foundry.toml b/foundry.toml index 9e5da040d..f665c7559 100644 --- a/foundry.toml +++ b/foundry.toml @@ -12,6 +12,7 @@ remappings = [ "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/" ] +sparse_mode = true # A list of ignored solc error codes From 4db3362f9fc12ab33612dfaaa56d3f25fb056a22 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:29:33 -0500 Subject: [PATCH 04/11] test(wip): todos --- src/test/unit/AllocationManagerUnit.t.sol | 387 ++++++++------------- src/test/unit/DelegationUnit.t.sol | 2 +- src/test/utils/EigenLayerUnitTestSetup.sol | 2 +- src/test/utils/Random.sol | 41 ++- 4 files changed, 187 insertions(+), 245 deletions(-) diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index faa338928..ade70c2fa 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -10,6 +10,10 @@ import "src/test/mocks/MockAVSRegistrar.sol"; contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManagerErrors, IAllocationManagerEvents { using SingleItemArrayLib for *; + /// ----------------------------------------------------------------------- + /// Constants + /// ----------------------------------------------------------------------- + /// NOTE: Raising these values directly increases cpu time for tests. uint256 internal constant FUZZ_MAX_ALLOCATIONS = 8; uint256 internal constant FUZZ_MAX_STRATS = 8; @@ -24,19 +28,22 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag uint32 constant ALLOCATION_CONFIGURATION_DELAY = 21 days / ASSUMED_BLOCK_TIME; uint32 constant DEFAULT_OPERATOR_ALLOCATION_DELAY = 1 days / ASSUMED_BLOCK_TIME; + /// ----------------------------------------------------------------------- + /// Mocks + /// ----------------------------------------------------------------------- + AllocationManager allocationManager; ERC20PresetFixedSupply tokenMock; StrategyBase strategyMock; + + /// ----------------------------------------------------------------------- + /// Defaults + /// ----------------------------------------------------------------------- + OperatorSet defaultOperatorSet; IStrategy[] defaultStrategies; - RegisterParams defaultRegisterParams; - DeregisterParams defaultDeregisterParams; - address defaultOperator = address(this); - address defaultAVS = address(0xFEDBAD); - - /// @dev Keeps track of an AVS's created operator sets so we can create more as needed - mapping(address avs => uint32) _opSetCount; + address defaultAVS = address(new MockAVSRegistrar()); /// ----------------------------------------------------------------------- /// Setup @@ -44,15 +51,8 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag function setUp() public virtual override { EigenLayerUnitTestSetup.setUp(); - - allocationManager = _deployAllocationManagerWithMockDependencies({ - _initialOwner: address(this), - _pauserRegistry: pauserRegistry, - _initialPausedStatus: 0 - }); - + _initializeAllocationManager(address(this), pauserRegistry, 0); tokenMock = new ERC20PresetFixedSupply("Mock Token", "MOCK", type(uint256).max, address(this)); - strategyMock = StrategyBase( address( new TransparentUpgradeableProxy( @@ -64,29 +64,11 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag ); defaultStrategies = strategyMock.toArray(); + defaultOperatorSet = OperatorSet(defaultAVS, 0); - /// Set up defaultAVS, defaultOperatorSet, and defaultOperator - - // Set the allocation delay & roll to when it can be set - delegationManagerMock.setIsOperator(defaultOperator, true); - cheats.prank(defaultOperator); - allocationManager.setAllocationDelay(DEFAULT_OPERATOR_ALLOCATION_DELAY); - cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); - - // Give the default AVS a contract to receive calls - cheats.etch(defaultAVS, type(MockAVSRegistrar).runtimeCode); - // Create a default operator set for the default AVS - defaultOperatorSet = _newOperatorSet_SingleMockStrategy(defaultAVS); - // Create a default register params - defaultRegisterParams = _newRegisterParams_SingleSet(defaultAVS, defaultOperatorSet.id); - - defaultDeregisterParams = DeregisterParams({ - operator: defaultOperator, - avs: defaultAVS, - operatorSetIds: defaultOperatorSet.id.toArrayU32() - }); - - // Register the default operator with the default operator set + _createOperatorSet(defaultOperatorSet, defaultStrategies); + _registerOperator(defaultOperator); + _setAllocationDelay(defaultOperator, DEFAULT_OPERATOR_ALLOCATION_DELAY); _registerForOperatorSet(defaultOperator, defaultOperatorSet); } @@ -94,12 +76,12 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag /// Internal Helpers /// ----------------------------------------------------------------------- - function _deployAllocationManagerWithMockDependencies( + function _initializeAllocationManager( address _initialOwner, IPauserRegistry _pauserRegistry, uint256 _initialPausedStatus - ) internal virtual returns (AllocationManager) { - return AllocationManager( + ) internal returns (AllocationManager) { + return allocationManager = AllocationManager( address( new TransparentUpgradeableProxy( address( @@ -117,158 +99,54 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag ); } - /// ----------------------------------------------------------------------- - /// Create operator sets - /// ----------------------------------------------------------------------- - - function _newOperatorSet(address avs, IStrategy[] memory strategies) internal returns (OperatorSet memory) { - uint32 nextId = _opSetCount[avs]; - _opSetCount[avs] = nextId + 1; - - OperatorSet memory operatorSet = OperatorSet(avs, nextId); - - cheats.prank(avs); - allocationManager.createOperatorSets( - CreateSetParams({operatorSetId: operatorSet.id, strategies: strategies}).toArray() - ); - - return operatorSet; + function _registerOperator( + address operator + ) internal { + delegationManagerMock.setIsOperator(operator, true); } - function _newOperatorSet_SingleMockStrategy( - address avs - ) internal returns (OperatorSet memory) { - uint32 nextId = _opSetCount[avs]; - _opSetCount[avs] = nextId + 1; - - OperatorSet memory operatorSet = OperatorSet(avs, nextId); - - cheats.prank(avs); - allocationManager.createOperatorSets( - CreateSetParams({operatorSetId: operatorSet.id, strategies: strategyMock.toArray()}).toArray() - ); - - return operatorSet; + function _setAllocationDelay(address operator, uint32 delay) internal { + cheats.prank(operator); + allocationManager.setAllocationDelay(delay); + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); } - /// @dev Create a single operator set with multiple configured strategies - function _newOperatorSet_MultipleStrategies( - address avs, - uint256 numStrategies - ) internal returns (OperatorSet memory) { - uint32 nextId = _opSetCount[avs]; - _opSetCount[avs] = nextId + 1; - - OperatorSet memory operatorSet = OperatorSet(avs, nextId); - IStrategy[] memory strategies = new IStrategy[](numStrategies); - - for (uint256 i = 0; i < numStrategies; i++) { - strategies[i] = IStrategy(random().Address()); - } - - cheats.prank(avs); + function _createOperatorSet(OperatorSet memory operatorSet, IStrategy[] memory strategies) internal returns (OperatorSet memory) { + cheats.prank(operatorSet.avs); allocationManager.createOperatorSets( CreateSetParams({operatorSetId: operatorSet.id, strategies: strategies}).toArray() ); - return operatorSet; } - function _newOperatorSets_SingleUniqueStrategy( - address avs, - uint256 numOpSets - ) internal returns (OperatorSet[] memory) { - OperatorSet[] memory operatorSets = new OperatorSet[](numOpSets); - CreateSetParams[] memory params = new CreateSetParams[](numOpSets); - - for (uint256 i = 0; i < numOpSets; i++) { - uint32 nextId = _opSetCount[avs]; - _opSetCount[avs] = nextId + 1; - - operatorSets[i] = OperatorSet(avs, nextId); - params[i].operatorSetId = nextId; - params[i].strategies = IStrategy(random().Address()).toArray(); - } - - cheats.prank(avs); - allocationManager.createOperatorSets(params); - - return operatorSets; - } - - function _newOperatorSets_SingleMockStrategy( - address avs, - uint8 numOpSets - ) internal returns (OperatorSet[] memory) { - OperatorSet[] memory operatorSets = new OperatorSet[](numOpSets); - CreateSetParams[] memory params = new CreateSetParams[](numOpSets); - - for (uint256 i = 0; i < numOpSets; i++) { - uint32 nextId = _opSetCount[avs]; - _opSetCount[avs] = nextId + 1; + function _createOperatorSets(OperatorSet[] memory operatorSets, IStrategy[] memory strategies) internal { + CreateSetParams[] memory createSetParams = new CreateSetParams[](operatorSets.length); - operatorSets[i] = OperatorSet(avs, nextId); - params[i].operatorSetId = nextId; - params[i].strategies = strategyMock.toArray(); + for (uint256 i; i < operatorSets.length; ++i) { + createSetParams[i] = CreateSetParams({operatorSetId: operatorSets[i].id, strategies: strategies}); } - cheats.prank(avs); - allocationManager.createOperatorSets(params); - - return operatorSets; + cheats.prank(operatorSets[0].avs); + allocationManager.createOperatorSets(createSetParams); } function _registerForOperatorSet(address operator, OperatorSet memory operatorSet) internal { - cheats.startPrank(operator); - + cheats.prank(operator); allocationManager.registerForOperatorSets( RegisterParams({avs: operatorSet.avs, operatorSetIds: operatorSet.id.toArrayU32(), data: ""}) ); - - cheats.stopPrank(); } - function _registerForOperatorSets(address operator, OperatorSet[] memory operatorSets) internal { + function _registerForOperatorSets(address operator, OperatorSet[] memory operatorSets) internal { cheats.startPrank(operator); - - for (uint256 i = 0; i < operatorSets.length; i++) { - RegisterParams memory params = - RegisterParams({avs: operatorSets[i].avs, operatorSetIds: operatorSets[i].id.toArrayU32(), data: ""}); - - allocationManager.registerForOperatorSets(params); + for (uint256 i; i < operatorSets.length; ++i) { + allocationManager.registerForOperatorSets( + RegisterParams({avs: operatorSets[i].avs, operatorSetIds: operatorSets[i].id.toArrayU32(), data: ""}) + ); } - cheats.stopPrank(); } - function _newRegisterParams_SingleSet( - address avs, - uint32 operatorSetId, - bytes memory data - ) internal pure returns (RegisterParams memory) { - return RegisterParams({avs: avs, operatorSetIds: operatorSetId.toArrayU32(), data: data}); - } - - function _newRegisterParams_SingleSet( - address avs, - uint32 operatorSetId - ) internal pure returns (RegisterParams memory) { - return RegisterParams({avs: avs, operatorSetIds: operatorSetId.toArrayU32(), data: ""}); - } - - /// ----------------------------------------------------------------------- - /// Random value generation - /// ----------------------------------------------------------------------- - - function _randSlashingParams(address operator, uint32 operatorSetId) internal returns (SlashingParams memory) { - return SlashingParams({ - operator: operator, - operatorSetId: operatorSetId, - wadToSlash: random().Uint256(1, WAD), - description: "test" - }); - } - /// ----------------------------------------------------------------------- /// Allocate/deallocate params /// ----------------------------------------------------------------------- @@ -281,7 +159,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); uint64[] memory newMagnitudes = new uint64[](strategies.length); - for (uint256 i = 0; i < strategies.length; i++) { + for (uint256 i; i < strategies.length; ++i) { newMagnitudes[i] = magnitude; } @@ -296,7 +174,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag ) internal view returns (AllocateParams[] memory) { AllocateParams[] memory allocateParams = new AllocateParams[](operatorSets.length); - for (uint256 i = 0; i < operatorSets.length; i++) { + for (uint256 i; i < operatorSets.length; ++i) { allocateParams[i] = _newAllocateParams(operatorSets[i], magnitude)[0]; } @@ -331,10 +209,10 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag } AllocateParams[] memory params = new AllocateParams[](magnitudes.length); - for (uint256 i = 0; i < params.length; i++) { + for (uint256 i; i < params.length; ++i) { params[i] = AllocateParams({ operatorSet: operatorSets[i], - strategies: strategyMock.toArray(), + strategies: defaultStrategies, newMagnitudes: magnitudes[i].toArrayU64() }); } @@ -374,10 +252,10 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag } AllocateParams[] memory params = new AllocateParams[](magnitudes.length); - for (uint256 i = 0; i < params.length; i++) { + for (uint256 i; i < params.length; ++i) { params[i] = AllocateParams({ operatorSet: operatorSets[i], - strategies: strategyMock.toArray(), + strategies: defaultStrategies, newMagnitudes: magnitudes[i].toArrayU64() }); } @@ -393,7 +271,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag AllocateParams[] memory deallocateParams = new AllocateParams[](allocateParams.length); // Generate a random deallocation for each operator set - for (uint256 i = 0; i < deallocateParams.length; ++i) { + for (uint256 i; i < deallocateParams.length; ++i) { deallocateParams[i] = AllocateParams({ operatorSet: allocateParams[i].operatorSet, strategies: allocateParams[i].strategies, @@ -432,7 +310,7 @@ contract AllocationManagerUnitTests_Initialization_Setters is AllocationManagerU // Deploy the contract with the expected initial state. uint256 initialPausedStatus = r.Uint256(); - AllocationManager alm = _deployAllocationManagerWithMockDependencies( + AllocationManager alm = _initializeAllocationManager( expectedInitialOwner, expectedPauserRegistry, initialPausedStatus ); @@ -458,6 +336,15 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests /// slashOperator() /// ----------------------------------------------------------------------- + function _randSlashingParams(address operator, uint32 operatorSetId) internal returns (SlashingParams memory) { + return SlashingParams({ + operator: operator, + operatorSetId: operatorSetId, + wadToSlash: random().Uint256(1, WAD), + description: "test" + }); + } + function test_revert_paused() public { allocationManager.pause(2 ** PAUSED_OPERATOR_SLASHING); cheats.expectRevert(IPausable.CurrentlyPaused.selector); @@ -887,7 +774,8 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); - OperatorSet memory operatorSet = _newOperatorSet_SingleMockStrategy(defaultAVS); + OperatorSet memory operatorSet = + _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); // Attempt to allocate AllocateParams[] memory allocateParams2 = _newAllocateParams(operatorSet, 1); @@ -1121,7 +1009,8 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint64 strategy1Magnitude = 5e17; uint64 strategy2Magnitude = WAD; - OperatorSet memory operatorSet = _newOperatorSet_MultipleStrategies(defaultAVS, 2); + OperatorSet memory operatorSet = OperatorSet(defaultAVS, random().Uint32()); + _createOperatorSet(operatorSet, random().StrategyArray(2)); _registerForOperatorSet(defaultOperator, operatorSet); IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); @@ -1159,7 +1048,7 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.slashOperator(slashingParams); // Check storage - for (uint256 i = 0; i < strategies.length; ++i) { + for (uint256 i; i < strategies.length; ++i) { assertEq( expectedEncumberedMags[i], allocationManager.encumberedMagnitude(defaultOperator, strategies[i]), @@ -1231,17 +1120,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests Allocation memory allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); assertEq(firstMod / 2, allocation.currentMagnitude, "currentMagnitude should be half of firstMod"); - console.log("value of pendingDiff: ", pendingDiff - pendingDiff / 2); assertEq( -int128(uint128(pendingDiff - pendingDiff / 2)), allocation.pendingDiff, "pendingDiff should be -secondMod" ); assertEq(deallocationEffectBlock, allocation.effectBlock, "effectBlock should be deallocationEffectBlock"); // Warp to deallocation effect block & clear deallocation queue - console.log("encumbered mag before: ", allocationManager.encumberedMagnitude(defaultOperator, strategyMock)); cheats.roll(deallocationEffectBlock); allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); - console.log("encumbered mag after: ", allocationManager.encumberedMagnitude(defaultOperator, strategyMock)); // Check expected max and allocatable uint64 expectedMaxMagnitude = WAD - firstMod / 2; @@ -1291,7 +1177,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe function test_revert_allocationDelayNotInEffect() public { address operator = address(0x2); - delegationManagerMock.setIsOperator(operator, true); + _registerOperator(operator); cheats.startPrank(operator); allocationManager.setAllocationDelay(5); @@ -1449,10 +1335,11 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe function testFuzz_allocate_singleStrat_multipleSets( Randomness r ) public rand(r) { - uint8 numOpSets = uint8(r.Uint256(1, type(uint8).max)); + uint8 numOpSets = uint8(r.Uint256(1, FUZZ_MAX_OP_SETS)); // Create and register for operator sets, each with a single default strategy - OperatorSet[] memory operatorSets = _newOperatorSets_SingleMockStrategy(defaultAVS, numOpSets); + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(operatorSets, defaultStrategies); _registerForOperatorSets(defaultOperator, operatorSets); // Get a random allocation for the operator sets @@ -1461,7 +1348,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Save vars to check against uint32 effectBlock = uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); uint64 usedMagnitude; - for (uint256 i = 0; i < allocateParams.length; ++i) { + for (uint256 i; i < allocateParams.length; ++i) { usedMagnitude += allocateParams[i].newMagnitudes[0]; } @@ -1491,7 +1378,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe assertEq(allocatedSets.length, numOpSets, "should have multiple allocated sets"); Allocation memory allocation; - for (uint256 i = 0; i < allocateParams.length; ++i) { + for (uint256 i; i < allocateParams.length; ++i) { allocation = allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock); assertEq(0, allocation.currentMagnitude, "currentMagnitude should not be updated"); assertEq( @@ -1510,7 +1397,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Check storage after roll to completion cheats.roll(effectBlock); - for (uint256 i = 0; i < allocateParams.length; ++i) { + for (uint256 i; i < allocateParams.length; ++i) { allocation = allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock); assertEq(allocateParams[i].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude not updated"); assertEq(0, allocation.pendingDiff, "pendingMagnitude not updated"); @@ -1565,8 +1452,8 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe uint8 numOpSets = uint8(r.Uint256(2, type(uint8).max)); // Create and register for operator sets - OperatorSet[] memory operatorSets = _newOperatorSets_SingleMockStrategy(defaultAVS, numOpSets); - _registerForOperatorSets(defaultOperator, operatorSets); + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(operatorSets, defaultStrategies); AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); uint256 randIdx = r.Uint256(0, allocateParams.length - 1); @@ -1583,14 +1470,15 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe Randomness r ) public rand(r) { // Create a handful of operator sets under the same AVS, each with a unique strategy - OperatorSet[] memory operatorSets = _newOperatorSets_SingleUniqueStrategy(defaultAVS, r.Uint256(2, 10)); + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, r.Uint256(2, 10)); + _createOperatorSets(operatorSets, defaultStrategies); // Register for each operator set _registerForOperatorSets(defaultOperator, operatorSets); // Allocate max to each operator set AllocateParams[] memory allocateParams = new AllocateParams[](operatorSets.length); - for (uint256 i = 0; i < operatorSets.length; i++) { + for (uint256 i; i < operatorSets.length; ++i) { allocateParams[i] = AllocateParams({ operatorSet: operatorSets[i], strategies: allocationManager.getStrategiesInOperatorSet(operatorSets[i]), @@ -1602,7 +1490,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.modifyAllocations(allocateParams); // Ensure encumbered magnitude is updated for each strategy - for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 i; i < allocateParams.length; ++i) { assertEq( WAD, allocationManager.encumberedMagnitude(defaultOperator, allocateParams[i].strategies[0]), @@ -1726,8 +1614,10 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe uint64 firstMod = r.Uint64(1, WAD); // Create a new operator sets that the operator is not registered for - OperatorSet memory operatorSetA = _newOperatorSet_SingleMockStrategy(defaultAVS); - OperatorSet memory operatorSetB = _newOperatorSet_SingleMockStrategy(defaultAVS); + OperatorSet memory operatorSetA = + _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); + OperatorSet memory operatorSetB = + _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); // Allocate magnitude to operator set AllocateParams[] memory allocateParams = _newAllocateParams(operatorSetA, firstMod); @@ -1787,8 +1677,11 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe function testFuzz_allocate_fromClearedDeallocQueue( Randomness r ) public rand(r) { + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); + // Create multiple operator sets, register, and allocate to each. Ensure all magnitude is fully allocated. - OperatorSet[] memory deallocSets = _newOperatorSets_SingleMockStrategy(defaultAVS, uint8(r.Uint256(1, 10))); + OperatorSet[] memory deallocSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(deallocSets, defaultStrategies); _registerForOperatorSets(defaultOperator, deallocSets); AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy_AllocAll(deallocSets); @@ -1828,7 +1721,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Create and register for a new operator set with the same default strategy. // If we try to allocate to this new set, it should clear the deallocation queue, // allowing all magnitude to be allocated - OperatorSet memory finalOpSet = _newOperatorSet_SingleMockStrategy(defaultAVS); + OperatorSet memory finalOpSet = _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); _registerForOperatorSet(defaultOperator, finalOpSet); AllocateParams[] memory finalAllocParams = _newAllocateParams(finalOpSet, WAD); @@ -1856,7 +1749,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe "all magnitude should be allocated" ); - for (uint256 i = 0; i < deallocSets.length; i++) { + for (uint256 i; i < deallocSets.length; ++i) { allocation = allocationManager.getAllocation(defaultOperator, deallocSets[i], strategyMock); assertEq(allocation.currentMagnitude, 0, "should not have any currently-allocated magnitude"); assertEq(allocation.pendingDiff, 0, "should have nothing pending"); @@ -1880,7 +1773,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Warp to completion and clear deallocation queue cheats.roll(block.number + DEALLOCATION_DELAY); - allocationManager.clearDeallocationQueue(defaultOperator, strategyMock.toArray(), uint16(1).toArrayU16()); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, uint16(1).toArrayU16()); // Check storage assertEq( @@ -1898,10 +1791,11 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe function testFuzz_allocate_deallocate_singleStrat_multipleOperatorSets( Randomness r ) public rand(r) { - uint8 numOpSets = uint8(r.Uint256(1, type(uint8).max)); + uint8 numOpSets = uint8(r.Uint256(1, FUZZ_MAX_OP_SETS)); // Create and register for operator sets, each with a single default strategy - OperatorSet[] memory operatorSets = _newOperatorSets_SingleMockStrategy(defaultAVS, numOpSets); + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(operatorSets, defaultStrategies); _registerForOperatorSets(defaultOperator, operatorSets); (AllocateParams[] memory allocateParams, AllocateParams[] memory deallocateParams) = @@ -1918,7 +1812,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Calculate post-deallocation magnitude // We can add each entry to this value because each operator set is using the same strategy uint64 postDeallocMag; - for (uint256 i = 0; i < deallocateParams.length; ++i) { + for (uint256 i; i < deallocateParams.length; ++i) { postDeallocMag += deallocateParams[i].newMagnitudes[0]; } cheats.prank(defaultOperator); @@ -1932,7 +1826,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe ); Allocation memory allocation; - for (uint256 i = 0; i < allocateParams.length; ++i) { + for (uint256 i; i < allocateParams.length; ++i) { allocation = allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, strategyMock); assertEq( allocateParams[i].newMagnitudes[0], @@ -1949,7 +1843,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Check storage after roll to completion cheats.roll(block.number + DEALLOCATION_DELAY); - for (uint256 i = 0; i < allocateParams.length; ++i) { + for (uint256 i; i < allocateParams.length; ++i) { allocation = allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, strategyMock); assertEq(deallocateParams[i].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude not updated"); assertEq(0, allocation.pendingDiff, "pendingMagnitude not updated"); @@ -1961,7 +1855,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe strategies[0] = strategyMock; uint16[] memory numToClear = new uint16[](1); numToClear[0] = numOpSets; - allocationManager.clearDeallocationQueue(defaultOperator, strategyMock.toArray(), type(uint16).max.toArrayU16()); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, type(uint16).max.toArrayU16()); // Check storage after clearing deallocation queue assertEq( postDeallocMag, @@ -1986,14 +1880,14 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.createOperatorSets(CreateSetParams(1, defaultStrategies).toArray()); cheats.startPrank(defaultOperator); - + allocationManager.setAllocationDelay(firstDelay); allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, half)); allocationManager.setAllocationDelay(secondDelay); cheats.roll(block.number + secondDelay); allocationManager.modifyAllocations(_newAllocateParams(OperatorSet(defaultAVS, 1), half)); - + cheats.stopPrank(); } @@ -2003,9 +1897,9 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe uint256 numAllocations = r.Uint256(2, FUZZ_MAX_ALLOCATIONS); uint256 numStrats = r.Uint256(2, FUZZ_MAX_STRATS); - AllocateParams[] memory allocateParams = r.allocateParams(defaultAVS, numAllocations, numStrats); - AllocateParams[] memory deallocateParams = r.deallocateParams(allocateParams); - CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + AllocateParams[] memory allocateParams = r.AllocateParams(defaultAVS, numAllocations, numStrats); + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); cheats.prank(defaultAVS); allocationManager.createOperatorSets(createSetParams); @@ -2013,23 +1907,31 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); - for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 i; i < allocateParams.length; ++i) { for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j]); + Allocation memory allocation = allocationManager.getAllocation( + defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] + ); assertEq(allocation.currentMagnitude, 0, "currentMagnitude not updated"); - assertEq(allocation.pendingDiff, int64(allocateParams[i].newMagnitudes[j]), "pendingMagnitude not updated"); - assertEq(allocation.effectBlock, block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY, "effectBlock not updated"); + assertEq( + allocation.pendingDiff, int64(allocateParams[i].newMagnitudes[j]), "pendingMagnitude not updated" + ); + assertEq( + allocation.effectBlock, block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY, "effectBlock not updated" + ); } } cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); - for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 i; i < allocateParams.length; ++i) { for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j]); - assertEq(allocation.currentMagnitude, allocateParams[i].newMagnitudes[j], "currentMagnitude not updated"); + Allocation memory allocation = allocationManager.getAllocation( + defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] + ); + assertEq( + allocation.currentMagnitude, allocateParams[i].newMagnitudes[j], "currentMagnitude not updated" + ); assertEq(allocation.pendingDiff, 0, "pendingMagnitude not updated"); assertEq(allocation.effectBlock, 0, "effectBlock not updated"); } @@ -2039,11 +1941,14 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.modifyAllocations(deallocateParams); // Deallocations are immediate if the operator's allocation is not slashable. - for (uint256 i = 0; i < allocateParams.length; i++) { + for (uint256 i; i < allocateParams.length; ++i) { for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j]); - assertEq(allocation.currentMagnitude, deallocateParams[i].newMagnitudes[j], "currentMagnitude not updated"); + Allocation memory allocation = allocationManager.getAllocation( + defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] + ); + assertEq( + allocation.currentMagnitude, deallocateParams[i].newMagnitudes[j], "currentMagnitude not updated" + ); assertEq(allocation.pendingDiff, 0, "pendingMagnitude not updated"); assertEq(allocation.effectBlock, 0, "effectBlock not updated"); } @@ -2189,7 +2094,8 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU assertEq(deallocationEffectBlock, allocation.effectBlock, "effect block not correct"); // Create and register for a new operator set - OperatorSet memory newOperatorSet = _newOperatorSet_SingleMockStrategy(defaultAVS); + OperatorSet memory newOperatorSet = + _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); _registerForOperatorSet(defaultOperator, newOperatorSet); // Allocate 33e16 mag to new operator set @@ -2198,8 +2104,6 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU cheats.prank(defaultOperator); allocationManager.modifyAllocations(secondAllocation); allocation = allocationManager.getAllocation(defaultOperator, newOperatorSet, strategyMock); - console.log("deallocation effect block: ", deallocationEffectBlock); - console.log("allocation effect block: ", allocationEffectBlock); assertEq(allocationEffectBlock, allocation.effectBlock, "effect block not correct"); assertLt(allocationEffectBlock, deallocationEffectBlock, "invalid test setup"); @@ -2243,7 +2147,8 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU cheats.roll(block.number + allocationDelay); // Create and register for a second operator set - OperatorSet memory newOperatorSet = _newOperatorSet_SingleMockStrategy(defaultAVS); + OperatorSet memory newOperatorSet = + _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); _registerForOperatorSet(defaultOperator, newOperatorSet); // Allocate half of mag to opset2 @@ -2289,13 +2194,10 @@ contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitT function setUp() public override { AllocationManagerUnitTests.setUp(); - - // Register operator - delegationManagerMock.setIsOperator(operatorToSet, true); + _registerOperator(operatorToSet); } function test_revert_callerNotOperator() public { - // Deregister operator delegationManagerMock.setIsOperator(operatorToSet, false); cheats.prank(operatorToSet); cheats.expectRevert(OperatorNotRegistered.selector); @@ -2409,6 +2311,15 @@ contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitT } contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + + RegisterParams defaultRegisterParams; + + function setUp() public override { + AllocationManagerUnitTests.setUp(); + defaultRegisterParams = RegisterParams(defaultAVS, defaultOperatorSet.id.toArrayU32(), ""); + } + function test_registerForOperatorSets_Paused() public { allocationManager.pause(2 ** PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION); cheats.expectRevert(IPausable.CurrentlyPaused.selector); @@ -2428,7 +2339,8 @@ contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManager ) public rand(r) { cheats.prank(defaultOperator); cheats.expectRevert(InvalidOperatorSet.selector); - allocationManager.registerForOperatorSets(_newRegisterParams_SingleSet(defaultAVS, 1)); // invalid id + defaultRegisterParams.operatorSetIds[0] = 1; // invalid id + allocationManager.registerForOperatorSets(defaultRegisterParams); // invalid id } function testFuzz_registerForOperatorSets_AlreadyMemberOfSet( @@ -2447,7 +2359,7 @@ contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManager uint32[] memory operatorSetIds = new uint32[](numOpSets); CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); - delegationManagerMock.setIsOperator(operator, true); + _registerOperator(operator); for (uint256 i; i < numOpSets; ++i) { operatorSetIds[i] = r.Uint32(1, type(uint32).max); @@ -2485,6 +2397,13 @@ contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManager contract AllocationManagerUnitTests_deregisterFromOperatorSets is AllocationManagerUnitTests { using SingleItemArrayLib for *; + DeregisterParams defaultDeregisterParams; + + function setUp() public override { + AllocationManagerUnitTests.setUp(); + defaultDeregisterParams = DeregisterParams(defaultOperator, defaultAVS, defaultOperatorSet.id.toArrayU32()); + } + function test_deregisterFromOperatorSets_Paused() public { allocationManager.pause(2 ** PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION); cheats.expectRevert(IPausable.CurrentlyPaused.selector); @@ -2534,7 +2453,7 @@ contract AllocationManagerUnitTests_deregisterFromOperatorSets is AllocationMana allocationManager.createOperatorSets(createSetParams); address operator = r.Address(); - delegationManagerMock.setIsOperator(operator, true); + _registerOperator(operator); cheats.prank(operator); allocationManager.registerForOperatorSets(RegisterParams(defaultAVS, operatorSetIds, "")); @@ -2621,7 +2540,7 @@ contract AllocationManagerUnitTests_removeStrategiesFromOperatorSet is Allocatio Randomness r ) public rand(r) { uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); - IStrategy[] memory strategies = r.strategyArray(numStrategies); + IStrategy[] memory strategies = r.StrategyArray(numStrategies); cheats.prank(defaultAVS); allocationManager.addStrategiesToOperatorSet(defaultOperatorSet.id, strategies); @@ -2665,7 +2584,7 @@ contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitT for (uint256 i; i < numOpSets; ++i) { createSetParams[i].operatorSetId = r.Uint32(1, type(uint32).max); - createSetParams[i].strategies = r.strategyArray(numStrategies); + createSetParams[i].strategies = r.StrategyArray(numStrategies); cheats.expectEmit(true, false, false, false, address(allocationManager)); emit OperatorSetCreated(OperatorSet(avs, createSetParams[i].operatorSetId)); for (uint256 j; j < numStrategies; ++j) { diff --git a/src/test/unit/DelegationUnit.t.sol b/src/test/unit/DelegationUnit.t.sol index 80f3f3ff9..6cadbd14a 100644 --- a/src/test/unit/DelegationUnit.t.sol +++ b/src/test/unit/DelegationUnit.t.sol @@ -2773,7 +2773,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { assertEq(depositScalingFactor, WAD, "bad test setup"); // Get withdrawable shares - (uint256[] memory withdrawableSharesBefore, uint256[] memory depositShares) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + (, uint256[] memory depositShares) = delegationManager.getWithdrawableShares(defaultStaker, strategies); // Format queued withdrawal ( diff --git a/src/test/utils/EigenLayerUnitTestSetup.sol b/src/test/utils/EigenLayerUnitTestSetup.sol index 9c1894a0b..82183e8c0 100644 --- a/src/test/utils/EigenLayerUnitTestSetup.sol +++ b/src/test/utils/EigenLayerUnitTestSetup.sol @@ -64,7 +64,7 @@ abstract contract EigenLayerUnitTestSetup is Test { pauserRegistry = new PauserRegistry(pausers, unpauser); eigenLayerProxyAdmin = new ProxyAdmin(); - + avsDirectoryMock = AVSDirectoryMock(payable(address(new AVSDirectoryMock()))); allocationManagerMock = AllocationManagerMock(payable(address(new AllocationManagerMock()))); strategyManagerMock = StrategyManagerMock(payable(address(new StrategyManagerMock(IDelegationManager(address(delegationManagerMock)))))); diff --git a/src/test/utils/Random.sol b/src/test/utils/Random.sol index 76a8b537c..4b6ae3cfc 100644 --- a/src/test/utils/Random.sol +++ b/src/test/utils/Random.sol @@ -106,14 +106,14 @@ library Random { /// General Types /// ----------------------------------------------------------------------- - function strategyArray(Randomness r, uint256 len) internal returns (IStrategy[] memory strategies) { + function StrategyArray(Randomness r, uint256 len) internal returns (IStrategy[] memory strategies) { strategies = new IStrategy[](len); for (uint256 i; i < len; ++i) { strategies[i] = IStrategy(r.Address()); } } - function operatorSetArray( + function OperatorSetArray( Randomness r, address avs, uint256 len @@ -129,7 +129,7 @@ library Random { /// ----------------------------------------------------------------------- /// @dev Usage: `r.createSetParams(r, numOpSets, numStrats)`. - function createSetParams( + function CreateSetParams( Randomness r, uint256 numOpSets, uint256 numStrats @@ -137,7 +137,7 @@ library Random { params = new IAllocationManagerTypes.CreateSetParams[](numOpSets); for (uint256 i; i < numOpSets; ++i) { params[i].operatorSetId = r.Uint32(1, type(uint32).max); - params[i].strategies = r.strategyArray(numStrats); + params[i].strategies = r.StrategyArray(numStrats); } } @@ -147,7 +147,7 @@ library Random { /// cheats.prank(avs); /// allocationManager.createOperatorSets(r.createSetParams(allocateParams)); /// ``` - function createSetParams( + function CreateSetParams( Randomness, IAllocationManagerTypes.AllocateParams[] memory allocateParams ) internal pure returns (IAllocationManagerTypes.CreateSetParams[] memory params) { @@ -170,7 +170,7 @@ library Random { /// cheats.prank(operator); /// allocationManager.modifyAllocations(allocateParams); /// ``` - function allocateParams( + function AllocateParams( Randomness r, address avs, uint256 numAllocations, @@ -183,7 +183,7 @@ library Random { for (uint256 i; i < numAllocations; ++i) { allocateParams[i].operatorSet = OperatorSet(avs, r.Uint32()); - allocateParams[i].strategies = r.strategyArray(numStrats); + allocateParams[i].strategies = r.StrategyArray(numStrats); allocateParams[i].newMagnitudes = new uint64[](numStrats); for (uint256 j; j < numStrats; ++j) { @@ -207,7 +207,7 @@ library Random { /// cheats.prank(operator) /// allocationManager.modifyAllocations(deallocateParams); /// ``` - function deallocateParams( + function DeallocateParams( Randomness r, IAllocationManagerTypes.AllocateParams[] memory allocateParams ) internal returns (IAllocationManagerTypes.AllocateParams[] memory deallocateParams) { @@ -223,7 +223,30 @@ library Random { for (uint256 j; j < allocateParams[i].strategies.length; ++j) { deallocateParams[i].newMagnitudes[j] = r.Uint64(0, allocateParams[i].newMagnitudes[j] - 1); } - } + } + } + + function RegisterParams( + Randomness r, + address avs, + uint256 numOpSets + ) internal returns (IAllocationManagerTypes.RegisterParams memory params) { + params.avs = avs; + params.operatorSetIds = new uint32[](numOpSets); + for (uint256 i; i < numOpSets; ++i) { + params.operatorSetIds[i] = r.Uint32(1, type(uint32).max); + } + params.data = abi.encode(r.Bytes32()); + } + + function DeregisterParams( + Randomness, + address operator, + IAllocationManagerTypes.RegisterParams memory registerParams + ) internal pure returns (IAllocationManagerTypes.DeregisterParams memory params) { + params.operator = operator; + params.avs = registerParams.avs; + params.operatorSetIds = registerParams.operatorSetIds; } /// ----------------------------------------------------------------------- From 87d1c9aa3eb7b2951886504dc25808380d9b319d Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:36:36 -0500 Subject: [PATCH 05/11] test(wip): todos --- src/test/unit/AllocationManagerUnit.t.sol | 536 +++++++++++----------- src/test/utils/SingleItemArrayLib.sol | 38 ++ 2 files changed, 310 insertions(+), 264 deletions(-) diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index ade70c2fa..c1b826885 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -111,7 +111,10 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); } - function _createOperatorSet(OperatorSet memory operatorSet, IStrategy[] memory strategies) internal returns (OperatorSet memory) { + function _createOperatorSet( + OperatorSet memory operatorSet, + IStrategy[] memory strategies + ) internal returns (OperatorSet memory) { cheats.prank(operatorSet.avs); allocationManager.createOperatorSets( CreateSetParams({operatorSetId: operatorSet.id, strategies: strategies}).toArray() @@ -137,7 +140,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag ); } - function _registerForOperatorSets(address operator, OperatorSet[] memory operatorSets) internal { + function _registerForOperatorSets(address operator, OperatorSet[] memory operatorSets) internal { cheats.startPrank(operator); for (uint256 i; i < operatorSets.length; ++i) { allocationManager.registerForOperatorSets( @@ -147,6 +150,17 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag cheats.stopPrank(); } + function _checkAllocation( + Allocation memory allocation, + uint256 expectedCurrentMagnitude, + int256 expectedPendingDiff, + uint256 expectedEffectBlock + ) internal pure { + assertEq(expectedCurrentMagnitude, allocation.currentMagnitude, "currentMagnitude != expected"); + assertEq(expectedPendingDiff, allocation.pendingDiff, "pendingDiff != expected"); + assertEq(expectedEffectBlock, allocation.effectBlock, "effectBlock != expected"); + } + /// ----------------------------------------------------------------------- /// Allocate/deallocate params /// ----------------------------------------------------------------------- @@ -310,9 +324,8 @@ contract AllocationManagerUnitTests_Initialization_Setters is AllocationManagerU // Deploy the contract with the expected initial state. uint256 initialPausedStatus = r.Uint256(); - AllocationManager alm = _initializeAllocationManager( - expectedInitialOwner, expectedPauserRegistry, initialPausedStatus - ); + AllocationManager alm = + _initializeAllocationManager(expectedInitialOwner, expectedPauserRegistry, initialPausedStatus); // Assert that the contract can only be initialized once. vm.expectRevert("Initializable: contract is already initialized"); @@ -369,40 +382,46 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.slashOperator(slashingParams); } - function test_revert_operatorNotSlashable() public { + function test_revert_NotMemberOfSet() public { cheats.prank(defaultAVS); cheats.expectRevert(NotMemberOfSet.selector); allocationManager.slashOperator(_randSlashingParams(random().Address(), 0)); } - // function test_revert_operatorNotAllocated() public { - // SlashingParams memory slashingParams = _randSlashingParams(defaultOperator, 0); - // // avsDirectoryMock.setIsOperatorSlashable(slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true); + function test_revert_operatorAllocated_notActive() public { + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + + cheats.prank(defaultAVS); + allocationManager.slashOperator( + SlashingParams({ + operator: defaultOperator, + operatorSetId: allocateParams[0].operatorSet.id, + wadToSlash: WAD, + description: "test" + }) + ); - // cheats.expectRevert(OperatorNotAllocated.selector); - // cheats.prank(defaultAVS); - // allocationManager.slashOperator(slashingParams); - // } + uint256 effectBlock = block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY; - // function test_revert_operatorAllocated_notActive() public { - // // Queue allocation - // AllocateParams[] memory allocateParams = - // _queueRandomAllocation_singleStrat_singleOpSet(defaultOperator, 0, 0); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: int64(allocateParams[0].newMagnitudes[0]), + expectedEffectBlock: effectBlock + }); - // // Setup data - // SlashingParams memory slashingParams = SlashingParams({ - // operator: defaultOperator, - // operatorSetId: allocateParams[0].operatorSet.id, - // wadToSlash: WAD, - // description: "test" - // }); - // // avsDirectoryMock.setIsOperatorSlashable(slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true); + cheats.roll(effectBlock); - // // Expect revert - // cheats.expectRevert(OperatorNotAllocated.selector); - // cheats.prank(defaultAVS); - // allocationManager.slashOperator(slashingParams); - // } + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: allocateParams[0].newMagnitudes[0], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); + } /** * Allocates all magnitude to for a single strategy to an operatorSet. Slashes 25% @@ -421,17 +440,15 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); // Slash operator for 25% - SlashingParams memory slashingParams = SlashingParams({ - operator: defaultOperator, - operatorSetId: defaultOperatorSet.id, - wadToSlash: 25e16, - description: "test" - }); - // // avsDirectoryMock.setIsOperatorSlashable(slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true); - - // Slash Operator cheats.prank(defaultAVS); - allocationManager.slashOperator(slashingParams); + allocationManager.slashOperator( + SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: 25e16, + description: "test" + }) + ); // Check storage assertEq( @@ -447,11 +464,12 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), "allocatableMagnitude shoudl be 0" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(75e16, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingDiff should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: 75e16, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } /// @notice Same test as above, but fuzzes the allocation @@ -487,13 +505,12 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0], "maxMagnitude not updated" ); - - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - - assertEq(expectedEncumberedMagnitude, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingDiff should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: expectedEncumberedMagnitude, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } /** @@ -546,20 +563,28 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0], "maxMagnitude not updated" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(magnitudeAfterSlash, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(5e17, allocation.pendingDiff, "pendingDiff should be for second alloc"); - assertEq(secondAllocEffectBlock, allocation.effectBlock, "effectBlock should be 0"); - // Warp to complete second allocation + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: magnitudeAfterSlash, + expectedPendingDiff: 5e17, + expectedEffectBlock: secondAllocEffectBlock + }); + cheats.roll(secondAllocEffectBlock); - uint64 allocatableMagnitude = allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock); - assertEq(0, allocatableMagnitude, "allocatableMagnitude should be 0"); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(75e16, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingDiff should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + + assertEq( + 0, + allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + "allocatableMagnitude should be 0" + ); + + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: 75e16, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } /** @@ -763,25 +788,23 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); // Slash operator for 100% - SlashingParams memory slashingParams = SlashingParams({ - operator: defaultOperator, - operatorSetId: allocateParams[0].operatorSet.id, - wadToSlash: WAD, - description: "test" - }); - - // Slash Operator cheats.prank(defaultAVS); - allocationManager.slashOperator(slashingParams); + allocationManager.slashOperator( + SlashingParams({ + operator: defaultOperator, + operatorSetId: allocateParams[0].operatorSet.id, + wadToSlash: WAD, + description: "test" + }) + ); OperatorSet memory operatorSet = _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); - - // Attempt to allocate AllocateParams[] memory allocateParams2 = _newAllocateParams(operatorSet, 1); - cheats.expectRevert(InsufficientMagnitude.selector); + // Attempt to allocate cheats.prank(defaultOperator); + cheats.expectRevert(InsufficientMagnitude.selector); allocationManager.modifyAllocations(allocateParams2); } @@ -793,42 +816,37 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests */ function test_allocateAll_deallocateAll() public { // Allocate all magnitude - AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); + allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, WAD)); cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); // Deallocate all - AllocateParams[] memory deallocateParams = _newAllocateParams(defaultOperatorSet, 0); cheats.prank(defaultOperator); - allocationManager.modifyAllocations(deallocateParams); - uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, 0)); // Slash operator for 100% - SlashingParams memory slashingParams = SlashingParams({ - operator: defaultOperator, - operatorSetId: defaultOperatorSet.id, - wadToSlash: WAD, - description: "test" - }); - // avsDirectoryMock.setIsOperatorSlashable(slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true); - - // Slash Operator cheats.prank(defaultAVS); - allocationManager.slashOperator(slashingParams); + allocationManager.slashOperator( + SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: WAD, + description: "test" + }) + ); - // Check storage post slash assertEq( 0, allocationManager.encumberedMagnitude(defaultOperator, strategyMock), "encumberedMagnitude not updated" ); assertEq( 0, allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0], "maxMagnitude not updated" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(0, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingDiff should be zero since everything is slashed"); - assertEq(deallocationEffectBlock, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: 0, + expectedEffectBlock: block.number + DEALLOCATION_DELAY + }); } /** @@ -903,99 +921,109 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests ); } - // /** - // * Allocates to multiple operatorSets for a strategy. Only slashes from one operatorSet. Validates - // * 1. The slashable shares of each operatorSet after magnitude allocation - // * 2. The first operatorSet has less slashable shares post slash - // * 3. The second operatorSet has the same number slashable shares post slash - // * 4. The PROPORTION that is slashable for opSet 2 has increased - // * 5. Encumbered magnitude, total allocatable magnitude - // */ - // function test_allocateMultipleOpsets_slashSingleOpset() public { - // // Set 100e18 shares for operator in DM - // uint256 operatorShares = 100e18; - // delegationManagerMock.setOperatorShares(defaultOperator, strategyMock, operatorShares); - // uint64 magnitudeToAllocate = 4e17; - - // // Allocate 40% to firstOperatorSet, 40% to secondOperatorSet - // AllocateParams[] memory allocateParams = new AllocateParams[](2); - // allocateParams[0] = _newAllocateParams(OperatorSet(defaultAVS, 1), magnitudeToAllocate)[0]; - // allocateParams[1] = _newAllocateParams(OperatorSet(defaultAVS, 2), magnitudeToAllocate)[0]; - // cheats.prank(defaultOperator); - // allocationManager.modifyAllocations(allocateParams); - // cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); - - // // Get slashable shares for each operatorSet - // address[] memory operatorArray = new address[](1); - // operatorArray[0] = defaultOperator; - // (, uint256[][] memory slashableSharesOpset1_preSlash) = allocationManager - // .getMinDelegatedAndSlashableOperatorSharesBefore( - // OperatorSet(defaultAVS, 1), operatorArray, defaultStrategies, uint32(block.number + 1) - // ); - // (, uint256[][] memory slashableSharesOpset2_preSlash) = allocationManager - // .getMinDelegatedAndSlashableOperatorSharesBefore( - // OperatorSet(defaultAVS, 2), operatorArray, defaultStrategies, uint32(block.number + 1) - // ); - // assertEq(40e18, slashableSharesOpset1_preSlash[0][0], "slashableShares of opSet_1 should be 40e18"); - // assertEq(40e18, slashableSharesOpset2_preSlash[0][0], "slashableShares of opSet_2 should be 40e18"); - // uint256 maxMagnitude = allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0]; - // uint256 opSet2PortionOfMaxMagnitude = uint256(magnitudeToAllocate) * WAD / maxMagnitude; - - // // Slash operator on operatorSet1 for 50% - // SlashingParams memory slashingParams = SlashingParams({ - // operator: defaultOperator, - // operatorSetId: allocateParams[0].operatorSet.id, - // wadToSlash: 5e17, - // description: "test" - // }); - // // avsDirectoryMock.setIsOperatorSlashable(slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true); - - // // Slash Operator - // cheats.prank(defaultAVS); - // allocationManager.slashOperator(slashingParams); - - // // Operator should now have 80e18 shares, since half of 40e18 was slashed - // delegationManagerMock.setOperatorShares(defaultOperator, strategyMock, 80e18); - - // // Check storage - // (, uint256[][] memory slashableSharesOpset1_postSlash) = allocationManager - // .getMinDelegatedAndSlashableOperatorSharesBefore( - // OperatorSet(defaultAVS, 1), operatorArray, defaultStrategies, uint32(block.number + 1) - // ); - // (, uint256[][] memory slashableSharesOpset2_postSlash) = allocationManager - // .getMinDelegatedAndSlashableOperatorSharesBefore( - // OperatorSet(defaultAVS, 2), operatorArray, defaultStrategies, uint32(block.number + 1) - // ); - - // assertEq(20e18, slashableSharesOpset1_postSlash[0][0], "slashableShares of opSet_1 should be 20e18"); - // assertEq( - // slashableSharesOpset2_preSlash[0][0], - // slashableSharesOpset2_postSlash[0][0], - // "slashableShares of opSet_2 should remain unchanged" - // ); - - // // Validate encumbered and total allocatable magnitude - // uint256 maxMagnitudeAfterSlash = allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0]; - // uint256 expectedEncumberedMagnitude = 6e17; // 4e17 from opSet2, 2e17 from opSet1 - // assertEq( - // expectedEncumberedMagnitude, - // allocationManager.encumberedMagnitude(defaultOperator, strategyMock), - // "encumberedMagnitude not updated" - // ); - // assertEq( - // maxMagnitudeAfterSlash - expectedEncumberedMagnitude, - // allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), - // "allocatableMagnitude should be diff of maxMagnitude and encumberedMagnitude" - // ); - - // // Check proportion after slash - // uint256 opSet2PortionOfMaxMagnitudeAfterSlash = uint256(magnitudeToAllocate) * WAD / maxMagnitudeAfterSlash; - // assertGt( - // opSet2PortionOfMaxMagnitudeAfterSlash, - // opSet2PortionOfMaxMagnitude, - // "opSet2 should have a greater proportion to slash from previous" - // ); - // } + /** + * Allocates to multiple operatorSets for a strategy. Only slashes from one operatorSet. Validates + * 1. The slashable shares of each operatorSet after magnitude allocation + * 2. The first operatorSet has less slashable shares post slash + * 3. The second operatorSet has the same number slashable shares post slash + * 4. The PROPORTION that is slashable for opSet 2 has increased + * 5. Encumbered magnitude, total allocatable magnitude + */ + function test_allocateMultipleOpsets_slashSingleOpset() public { + // Set 100e18 shares for operator in DM + uint256 operatorShares = 100e18; + delegationManagerMock.setOperatorShares(defaultOperator, strategyMock, operatorShares); + uint64 magnitudeToAllocate = 4e17; + + OperatorSet memory operatorSet = OperatorSet(defaultAVS, 1); + OperatorSet memory operatorSet2 = OperatorSet(defaultAVS, 2); + + // Allocate 40% to firstOperatorSet, 40% to secondOperatorSet + AllocateParams[] memory allocateParams = new AllocateParams[](2); + allocateParams[0] = _newAllocateParams( + _createOperatorSet(OperatorSet(defaultAVS, 1), defaultStrategies), magnitudeToAllocate + )[0]; + allocateParams[1] = _newAllocateParams( + _createOperatorSet(OperatorSet(defaultAVS, 2), defaultStrategies), magnitudeToAllocate + )[0]; + + _registerForOperatorSet(defaultOperator, operatorSet); + _registerForOperatorSet(defaultOperator, operatorSet2); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Get slashable shares for each operatorSet + address[] memory operatorArray = new address[](1); + operatorArray[0] = defaultOperator; + // (, uint256[][] memory slashableSharesOpset1_preSlash) = allocationManager + // .getMinDelegatedAndSlashableOperatorSharesBefore( + // OperatorSet(defaultAVS, 1), operatorArray, defaultStrategies, uint32(block.number + 1) + // ); + // (, uint256[][] memory slashableSharesOpset2_preSlash) = allocationManager + // .getMinDelegatedAndSlashableOperatorSharesBefore( + // OperatorSet(defaultAVS, 2), operatorArray, defaultStrategies, uint32(block.number + 1) + // ); + // assertEq(40e18, slashableSharesOpset1_preSlash[0][0], "slashableShares of opSet_1 should be 40e18"); + // assertEq(40e18, slashableSharesOpset2_preSlash[0][0], "slashableShares of opSet_2 should be 40e18"); + uint256 maxMagnitude = allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0]; + uint256 opSet2PortionOfMaxMagnitude = uint256(magnitudeToAllocate) * WAD / maxMagnitude; + + // Slash operator on operatorSet1 for 50% + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: allocateParams[0].operatorSet.id, + wadToSlash: 5e17, + description: "test" + }); + + // Slash Operator + cheats.prank(defaultAVS); + allocationManager.slashOperator(slashingParams); + + // Operator should now have 80e18 shares, since half of 40e18 was slashed + delegationManagerMock.setOperatorShares(defaultOperator, strategyMock, 80e18); + + // // Check storage + // (, uint256[][] memory slashableSharesOpset1_postSlash) = allocationManager + // .getMinDelegatedAndSlashableOperatorSharesBefore( + // OperatorSet(defaultAVS, 1), operatorArray, defaultStrategies, uint32(block.number + 1) + // ); + // (, uint256[][] memory slashableSharesOpset2_postSlash) = allocationManager + // .getMinDelegatedAndSlashableOperatorSharesBefore( + // OperatorSet(defaultAVS, 2), operatorArray, defaultStrategies, uint32(block.number + 1) + // ); + + // assertEq(20e18, slashableSharesOpset1_postSlash[0][0], "slashableShares of opSet_1 should be 20e18"); + // assertEq( + // slashableSharesOpset2_preSlash[0][0], + // slashableSharesOpset2_postSlash[0][0], + // "slashableShares of opSet_2 should remain unchanged" + // ); + + // Validate encumbered and total allocatable magnitude + uint256 maxMagnitudeAfterSlash = allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0]; + uint256 expectedEncumberedMagnitude = 6e17; // 4e17 from opSet2, 2e17 from opSet1 + assertEq( + expectedEncumberedMagnitude, + allocationManager.encumberedMagnitude(defaultOperator, strategyMock), + "encumberedMagnitude not updated" + ); + assertEq( + maxMagnitudeAfterSlash - expectedEncumberedMagnitude, + allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + "allocatableMagnitude should be diff of maxMagnitude and encumberedMagnitude" + ); + + // Check proportion after slash + uint256 opSet2PortionOfMaxMagnitudeAfterSlash = uint256(magnitudeToAllocate) * WAD / maxMagnitudeAfterSlash; + assertGt( + opSet2PortionOfMaxMagnitudeAfterSlash, + opSet2PortionOfMaxMagnitude, + "opSet2 should have a greater proportion to slash from previous" + ); + } /** * Allocates to multiple strategies for the given operatorSetKey. Slashes from both strategies Validates a slash propogates to both strategies. @@ -1066,93 +1094,82 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests } } - /** - * Allocates magnitude. Deallocates some. Slashes a portion, and then allocates up to the max available magnitude - * TODO: Fuzz the wadsToSlash - */ + /// @dev Allocates magnitude. Deallocates some. Slashes a portion, and then allocates up to the max available magnitude function testFuzz_allocate_deallocate_slashWhilePending_allocateMax( Randomness r ) public rand(r) { - // Bound allocation and deallocation - uint64 firstMod = r.Uint64(3, WAD); - uint64 secondMod = r.Uint64(1, firstMod - 2); + AllocateParams[] memory allocateParams = r.AllocateParams({avs: defaultAVS, numAllocations: 1, numStrats: 1}); + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); + OperatorSet memory operatorSet = allocateParams[0].operatorSet; + IStrategy strategy = allocateParams[0].strategies[0]; - // TODO: remove these assumptions around even numbers - if (firstMod % 2 != 0) { - firstMod += 1; - } - if (secondMod % 2 != 0) { - secondMod += 1; - } - uint64 pendingDiff = firstMod - secondMod; + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(createSetParams); - // Allocate magnitude - AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstMod); - cheats.prank(defaultOperator); + _registerForOperatorSet(defaultOperator, operatorSet); + + // Allocate some magnitude, then deallocate some. + cheats.startPrank(defaultOperator); allocationManager.modifyAllocations(allocateParams); cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); - - // Deallocate magnitude - AllocateParams[] memory deallocateParams = _newAllocateParams(defaultOperatorSet, secondMod); - cheats.prank(defaultOperator); allocationManager.modifyAllocations(deallocateParams); - uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + cheats.roll(block.number + DEALLOCATION_DELAY); + cheats.stopPrank(); - // Slash operator for 50% + // Slash operator for some random amount (1% -> 99%). SlashingParams memory slashingParams = SlashingParams({ operator: defaultOperator, - operatorSetId: defaultOperatorSet.id, - wadToSlash: 5e17, + operatorSetId: operatorSet.id, + wadToSlash: r.Uint64(0.01 ether, 0.99 ether), description: "test" }); - // avsDirectoryMock.setIsOperatorSlashable(slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true); + + uint256 magnitudeBeforeSlash = deallocateParams[0].newMagnitudes[0]; + uint256 slashedMagnitude = magnitudeBeforeSlash * slashingParams.wadToSlash / WAD; + uint256 currentMagnitude = magnitudeBeforeSlash - slashedMagnitude - 1; + uint256 maxMagnitude = WAD - slashedMagnitude - 1; - // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); - // Check storage post slash assertEq( - firstMod / 2, - allocationManager.encumberedMagnitude(defaultOperator, strategyMock), + currentMagnitude, + allocationManager.encumberedMagnitude(defaultOperator, strategy), "encumberedMagnitude should be half of firstMod" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(firstMod / 2, allocation.currentMagnitude, "currentMagnitude should be half of firstMod"); - assertEq( - -int128(uint128(pendingDiff - pendingDiff / 2)), allocation.pendingDiff, "pendingDiff should be -secondMod" - ); - assertEq(deallocationEffectBlock, allocation.effectBlock, "effectBlock should be deallocationEffectBlock"); - // Warp to deallocation effect block & clear deallocation queue - cheats.roll(deallocationEffectBlock); - allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSet, strategy), + expectedCurrentMagnitude: uint64(currentMagnitude), + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); + + // Clear deallocation queue. + allocationManager.clearDeallocationQueue(defaultOperator, strategy.toArray(), _maxNumToClear()); - // Check expected max and allocatable - uint64 expectedMaxMagnitude = WAD - firstMod / 2; assertEq( - expectedMaxMagnitude, - allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0], + maxMagnitude, + allocationManager.getMaxMagnitudes(defaultOperator, strategy.toArray())[0], "maxMagnitude should be expectedMaxMagnitude" ); - // Allocatable is expectedMax - currentMagPostSlashing - pendingDiffOfDeallocateParams post slashing - uint64 expectedAllocatable = expectedMaxMagnitude - ((firstMod / 2) - (pendingDiff - pendingDiff / 2)); + assertEq( - expectedAllocatable, - allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + maxMagnitude - currentMagnitude, + allocationManager.getAllocatableMagnitude(defaultOperator, strategy), "allocatableMagnitude should be expectedAllocatable" ); // Allocate up to max magnitude - AllocateParams[] memory allocateParams2 = _newAllocateParams(defaultOperatorSet, expectedMaxMagnitude); + AllocateParams[] memory allocateParams2 = _newAllocateParams(operatorSet, uint64(maxMagnitude)); cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams2); // Assert that encumbered is expectedMaxMagnitude assertEq( 0, - allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + allocationManager.getAllocatableMagnitude(defaultOperator, strategy), "allocatableMagnitude should be 0" ); } @@ -1466,34 +1483,27 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.modifyAllocations(allocateParams); } - function test_allocateMaxToMultipleStrategies( + function testFuzz_allocateMaxToMultipleStrategies( Randomness r ) public rand(r) { - // Create a handful of operator sets under the same AVS, each with a unique strategy - OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, r.Uint256(2, 10)); - _createOperatorSets(operatorSets, defaultStrategies); + uint256 numStrats = r.Uint256(2, FUZZ_MAX_STRATS); - // Register for each operator set - _registerForOperatorSets(defaultOperator, operatorSets); + OperatorSet memory operatorSet = OperatorSet(defaultAVS, r.Uint32()); + IStrategy[] memory strategies = r.StrategyArray(numStrats); - // Allocate max to each operator set - AllocateParams[] memory allocateParams = new AllocateParams[](operatorSets.length); - for (uint256 i; i < operatorSets.length; ++i) { - allocateParams[i] = AllocateParams({ - operatorSet: operatorSets[i], - strategies: allocationManager.getStrategiesInOperatorSet(operatorSets[i]), - newMagnitudes: WAD.toArrayU64() - }); - } + _createOperatorSet(operatorSet, strategies); + _registerForOperatorSet(defaultOperator, operatorSet); cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); + allocationManager.modifyAllocations( + AllocateParams({operatorSet: operatorSet, strategies: strategies, newMagnitudes: WAD.toArrayU64(numStrats)}) + .toArray() + ); - // Ensure encumbered magnitude is updated for each strategy - for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 i; i < numStrats; ++i) { assertEq( WAD, - allocationManager.encumberedMagnitude(defaultOperator, allocateParams[i].strategies[0]), + allocationManager.encumberedMagnitude(defaultOperator, strategies[i]), "encumberedMagnitude not max" ); } @@ -1614,10 +1624,8 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe uint64 firstMod = r.Uint64(1, WAD); // Create a new operator sets that the operator is not registered for - OperatorSet memory operatorSetA = - _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); - OperatorSet memory operatorSetB = - _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); + OperatorSet memory operatorSetA = _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); + OperatorSet memory operatorSetB = _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); // Allocate magnitude to operator set AllocateParams[] memory allocateParams = _newAllocateParams(operatorSetA, firstMod); diff --git a/src/test/utils/SingleItemArrayLib.sol b/src/test/utils/SingleItemArrayLib.sol index f337fe8cb..61ace04fe 100644 --- a/src/test/utils/SingleItemArrayLib.sol +++ b/src/test/utils/SingleItemArrayLib.sol @@ -5,6 +5,10 @@ import "src/contracts/interfaces/IAllocationManager.sol"; /// @dev Helper library for simplifying the syntax for creating single item arrays for inputs. library SingleItemArrayLib { + /// ----------------------------------------------------------------------- + /// Native Types + /// ----------------------------------------------------------------------- + function toArrayU16( uint16 x ) internal pure returns (uint16[] memory array) { @@ -26,6 +30,36 @@ library SingleItemArrayLib { array[0] = x; } + function toArrayU16( + uint16 x, + uint256 len + ) internal pure returns (uint16[] memory array) { + array = new uint16[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + + function toArrayU32( + uint32 x, + uint256 len + ) internal pure returns (uint32[] memory array) { + array = new uint32[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + + function toArrayU64( + uint64 x, + uint256 len + ) internal pure returns (uint64[] memory array) { + array = new uint64[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + function toArray( IStrategy strategy ) internal pure returns (IStrategy[] memory array) { @@ -33,6 +67,10 @@ library SingleItemArrayLib { array[0] = strategy; } + /// ----------------------------------------------------------------------- + /// EigenLayer Types + /// ----------------------------------------------------------------------- + function toArray( OperatorSet memory operatorSet ) internal pure returns (OperatorSet[] memory array) { From 17a584751d0d4a96f5fee6b9c28277929ef27b4a Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Thu, 7 Nov 2024 21:17:32 -0500 Subject: [PATCH 06/11] test(wip): todos --- src/test/unit/AllocationManagerUnit.t.sol | 318 +++++++++++----------- 1 file changed, 161 insertions(+), 157 deletions(-) diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index c1b826885..e8e55c71c 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -753,26 +753,30 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0], "maxMagnitude not updated" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(magnitudeAfterSlash, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq( - -int128(uint128((uint64(magnitudeAfterDeallocationSlash)))), - allocation.pendingDiff, - "pendingDiff should be decreased after slash" - ); - assertEq(deallocationEffectBlock, allocation.effectBlock, "effectBlock should be 0"); + + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: magnitudeAfterSlash, + expectedPendingDiff: -int128(uint128((uint64(magnitudeAfterDeallocationSlash)))), + expectedEffectBlock: deallocationEffectBlock + }); // Check storage after complete modification cheats.roll(deallocationEffectBlock); allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(magnitudeAfterDeallocationSlash, allocation.currentMagnitude, "currentMagnitude not updated"); + assertEq( magnitudeAfterDeallocationSlash, maxMagnitudeAfterSlash / 2, "magnitude after deallocation should be half of max magnitude, since we originally deallocated by half" ); + + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: magnitudeAfterDeallocationSlash, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } /** @@ -869,11 +873,12 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); // Check storage post deallocation - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(WAD, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(-5e17, allocation.pendingDiff, "pendingDiff should be 5e17 after deallocation"); - assertEq(deallocationEffectBlock, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: WAD, + expectedPendingDiff: -5e17, + expectedEffectBlock: deallocationEffectBlock + }); // Warp to deallocation effect block cheats.roll(deallocationEffectBlock); @@ -905,15 +910,17 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.getMaxMagnitudes(defaultOperator, defaultStrategies)[0], "maxMagnitude not updated" ); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(magnitudeAfterSlash, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingDiff should be 0 after slash"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: magnitudeAfterSlash, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); + uint64 allocatableMagnitudeAfterSlash = allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock); - // Check storage after complete modification. Expect encumberedMag to be emitted again + // Check storage after complete modification. allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); assertEq( allocatableMagnitudeAfterSlash, allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), @@ -1087,10 +1094,12 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.getAllocatableMagnitude(defaultOperator, strategies[i]), "allocatableMagnitude not updated" ); - Allocation memory allocation = allocationManager.getAllocation(defaultOperator, operatorSet, strategies[i]); - assertEq(expectedMagnitudeAfterSlash[i], allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingDiff should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSet, strategies[i]), + expectedCurrentMagnitude: expectedMagnitudeAfterSlash[i], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } } @@ -1124,7 +1133,7 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests wadToSlash: r.Uint64(0.01 ether, 0.99 ether), description: "test" }); - + uint256 magnitudeBeforeSlash = deallocateParams[0].newMagnitudes[0]; uint256 slashedMagnitude = magnitudeBeforeSlash * slashingParams.wadToSlash / WAD; uint256 currentMagnitude = magnitudeBeforeSlash - slashedMagnitude - 1; @@ -1168,9 +1177,7 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests // Assert that encumbered is expectedMaxMagnitude assertEq( - 0, - allocationManager.getAllocatableMagnitude(defaultOperator, strategy), - "allocatableMagnitude should be 0" + 0, allocationManager.getAllocatableMagnitude(defaultOperator, strategy), "allocatableMagnitude should be 0" ); } } @@ -1335,18 +1342,21 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), "allocatableMagnitude not calcualted correctly" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(0, allocation.currentMagnitude, "currentMagnitude should not be updated"); - assertEq(int128(uint128(magnitude)), allocation.pendingDiff, "pendingMagnitude not updated"); - assertEq(effectBlock, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: int128(uint128(magnitude)), + expectedEffectBlock: effectBlock + }); // Check storage after roll to completion cheats.roll(effectBlock); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(magnitude, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude not updated"); - assertEq(0, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: magnitude, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } function testFuzz_allocate_singleStrat_multipleSets( @@ -1396,29 +1406,28 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe Allocation memory allocation; for (uint256 i; i < allocateParams.length; ++i) { - allocation = allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock); - assertEq(0, allocation.currentMagnitude, "currentMagnitude should not be updated"); - assertEq( - int128(uint128(allocateParams[i].newMagnitudes[0])), - allocation.pendingDiff, - "pendingMagnitude not updated" - ); - assertEq(effectBlock, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: int128(uint128(allocateParams[i].newMagnitudes[0])), + expectedEffectBlock: effectBlock + }); allocatedStrats = allocationManager.getAllocatedStrategies(defaultOperator, operatorSets[i]); assertEq(allocatedStrats.length, 1, "should have a single allocated strategy to each set"); assertEq(address(allocatedStrats[0]), address(strategyMock), "should have allocated default strat"); - assertEq(allocatedSets[i].key(), operatorSets[i].key(), "should be allocated to expected set"); } // Check storage after roll to completion cheats.roll(effectBlock); for (uint256 i; i < allocateParams.length; ++i) { - allocation = allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock); - assertEq(allocateParams[i].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude not updated"); - assertEq(0, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), + expectedCurrentMagnitude: allocateParams[i].newMagnitudes[0], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } } @@ -1580,20 +1589,24 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), "allocatableMagnitude not calcualted correctly" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(firstMod, allocation.currentMagnitude, "currentMagnitude should not be updated"); - int128 expectedDiff = -int128(uint128(firstMod - secondMod)); - assertEq(expectedDiff, allocation.pendingDiff, "pendingMagnitude not updated"); + uint32 effectBlock = uint32(block.number + DEALLOCATION_DELAY); - assertEq(effectBlock, allocation.effectBlock, "effectBlock not updated"); + + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: firstMod, + expectedPendingDiff: -int128(uint128(firstMod - secondMod)), + expectedEffectBlock: effectBlock + }); // Check storage after roll to completion cheats.roll(effectBlock); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(secondMod, allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude not updated"); - assertEq(0, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: secondMod, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); assertEq( firstMod, allocationManager.encumberedMagnitude(defaultOperator, strategyMock), @@ -1601,11 +1614,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe ); // Check storage after clearing deallocation queue - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; - uint16[] memory numToClear = new uint16[](1); - numToClear[0] = 1; - allocationManager.clearDeallocationQueue(defaultOperator, strategies, numToClear); + allocationManager.clearDeallocationQueue(defaultOperator, strategyMock.toArray(), uint16(1).toArrayU16()); assertEq( secondMod, allocationManager.encumberedMagnitude(defaultOperator, strategyMock), @@ -1662,20 +1671,20 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe ); // Check operator set A - Allocation memory allocation = allocationManager.getAllocation(defaultOperator, operatorSetA, strategyMock); - assertEq(0, allocation.currentMagnitude, "currentMagnitude should equal 0"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSetA, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); // Check operator set B - allocation = allocationManager.getAllocation(defaultOperator, operatorSetB, strategyMock); - assertEq(0, allocation.currentMagnitude, "currentMagnitude should equal 0"); - assertEq(firstMod, uint64(uint128(allocation.pendingDiff)), "pendingMagnitude should be firstMod"); - assertEq( - uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY), - allocation.effectBlock, - "effectBlock should be expected" - ); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSetB, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: int64(firstMod), + expectedEffectBlock: block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY + }); } /** @@ -1738,14 +1747,12 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Check that all magnitude will be allocated to the new set, and each prior set // has a zeroed-out allocation - Allocation memory allocation = allocationManager.getAllocation(defaultOperator, finalOpSet, strategyMock); - assertEq(allocation.currentMagnitude, 0, "should not have any currently-allocated magnitude"); - assertEq(uint64(uint128(allocation.pendingDiff)), WAD, "should have 1 WAD pending"); - assertEq( - allocation.effectBlock, - uint32(block.number) + DEFAULT_OPERATOR_ALLOCATION_DELAY, - "should be effective after default delay" - ); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, finalOpSet, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: int64(WAD), + expectedEffectBlock: block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY + }); assertEq( allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), 0, @@ -1758,10 +1765,12 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe ); for (uint256 i; i < deallocSets.length; ++i) { - allocation = allocationManager.getAllocation(defaultOperator, deallocSets[i], strategyMock); - assertEq(allocation.currentMagnitude, 0, "should not have any currently-allocated magnitude"); - assertEq(allocation.pendingDiff, 0, "should have nothing pending"); - assertEq(allocation.effectBlock, 0, "should be zeroed out"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, deallocSets[i], strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } } @@ -1789,11 +1798,12 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.encumberedMagnitude(defaultOperator, strategyMock), "encumberedMagnitude should be updated" ); - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(0, allocation.currentMagnitude, "currentMagnitude should be 0"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: 0, + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } function testFuzz_allocate_deallocate_singleStrat_multipleOperatorSets( @@ -1835,34 +1845,27 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe Allocation memory allocation; for (uint256 i; i < allocateParams.length; ++i) { - allocation = allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, strategyMock); - assertEq( - allocateParams[i].newMagnitudes[0], - allocation.currentMagnitude, - "currentMagnitude should not be updated" - ); - int128 expectedDiff = - -int128(uint128(allocateParams[i].newMagnitudes[0] - deallocateParams[i].newMagnitudes[0])); - assertEq(expectedDiff, allocation.pendingDiff, "pendingMagnitude not updated"); - uint32 effectBlock = uint32(block.number + DEALLOCATION_DELAY); - assertEq(effectBlock, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), + expectedCurrentMagnitude: allocateParams[i].newMagnitudes[0], + expectedPendingDiff: -int64(allocateParams[i].newMagnitudes[0] - deallocateParams[i].newMagnitudes[0]), + expectedEffectBlock: block.number + DEALLOCATION_DELAY + }); } // Check storage after roll to completion cheats.roll(block.number + DEALLOCATION_DELAY); for (uint256 i; i < allocateParams.length; ++i) { - allocation = allocationManager.getAllocation(defaultOperator, allocateParams[i].operatorSet, strategyMock); - assertEq(deallocateParams[i].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude not updated"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude not updated"); - assertEq(0, allocation.effectBlock, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), + expectedCurrentMagnitude: deallocateParams[i].newMagnitudes[0], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } // Clear deallocation queue - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; - uint16[] memory numToClear = new uint16[](1); - numToClear[0] = numOpSets; allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, type(uint16).max.toArrayU16()); // Check storage after clearing deallocation queue assertEq( @@ -1874,7 +1877,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe /// @dev Set allocation delay > ALLOCATION_CONFIGURATION_DELAY, allocate, /// set allocation delay to < ALLOCATION_CONFIGURATION_DELAY, allocate again - /// once new delay is set. + /// once new delay is sect. /// /// NOTE: Should be able to allocate faster than `ALLOCATION_CONFIGURATION_DELAY`. function testFuzz_modifyAllocations_ShouldBeAbleToAllocateSoonerThanLastDelay( @@ -1917,16 +1920,14 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe for (uint256 i; i < allocateParams.length; ++i) { for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { - Allocation memory allocation = allocationManager.getAllocation( - defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] - ); - assertEq(allocation.currentMagnitude, 0, "currentMagnitude not updated"); - assertEq( - allocation.pendingDiff, int64(allocateParams[i].newMagnitudes[j]), "pendingMagnitude not updated" - ); - assertEq( - allocation.effectBlock, block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY, "effectBlock not updated" - ); + _checkAllocation({ + allocation: allocationManager.getAllocation( + defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] + ), + expectedCurrentMagnitude: 0, + expectedPendingDiff: int64(allocateParams[i].newMagnitudes[j]), + expectedEffectBlock: block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY + }); } } @@ -1934,14 +1935,14 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe for (uint256 i; i < allocateParams.length; ++i) { for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { - Allocation memory allocation = allocationManager.getAllocation( - defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] - ); - assertEq( - allocation.currentMagnitude, allocateParams[i].newMagnitudes[j], "currentMagnitude not updated" - ); - assertEq(allocation.pendingDiff, 0, "pendingMagnitude not updated"); - assertEq(allocation.effectBlock, 0, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation( + defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] + ), + expectedCurrentMagnitude: allocateParams[i].newMagnitudes[j], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } } @@ -1951,14 +1952,14 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Deallocations are immediate if the operator's allocation is not slashable. for (uint256 i; i < allocateParams.length; ++i) { for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { - Allocation memory allocation = allocationManager.getAllocation( - defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] - ); - assertEq( - allocation.currentMagnitude, deallocateParams[i].newMagnitudes[j], "currentMagnitude not updated" - ); - assertEq(allocation.pendingDiff, 0, "pendingMagnitude not updated"); - assertEq(allocation.effectBlock, 0, "effectBlock not updated"); + _checkAllocation({ + allocation: allocationManager.getAllocation( + defaultOperator, allocateParams[i].operatorSet, allocateParams[i].strategies[j] + ), + expectedCurrentMagnitude: deallocateParams[i].newMagnitudes[j], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } } } @@ -2014,11 +2015,12 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU assertEq(0, entries.length, "should not have emitted any events 2"); // Validate allocation is no longer pending - Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(allocateParams[0].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude should be 0"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: allocateParams[0].newMagnitudes[0], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } /** @@ -2055,12 +2057,12 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU ); // Validate storage - encumbered magnitude should just be allocateParams (we only have 1 allocation) - IAllocationManager.Allocation memory allocation = - allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - int128 pendingDiff = -int128(uint128(allocateParams[0].newMagnitudes[0] - deallocateParams[0].newMagnitudes[0])); - assertEq(allocateParams[0].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude should be 0"); - assertEq(pendingDiff, allocation.pendingDiff, "pendingMagnitude should be 0"); - assertEq(block.number + DEALLOCATION_DELAY, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: allocateParams[0].newMagnitudes[0], + expectedPendingDiff: -int128(uint128(allocateParams[0].newMagnitudes[0] - deallocateParams[0].newMagnitudes[0])), + expectedEffectBlock: block.number + DEALLOCATION_DELAY + }); // Warp to deallocation complete block cheats.roll(block.number + DEALLOCATION_DELAY); @@ -2074,10 +2076,12 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU allocationManager.encumberedMagnitude(defaultOperator, strategyMock), "encumberedMagnitude should be updated" ); - allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); - assertEq(deallocateParams[0].newMagnitudes[0], allocation.currentMagnitude, "currentMagnitude should be 0"); - assertEq(0, allocation.pendingDiff, "pendingMagnitude should be 0"); - assertEq(0, allocation.effectBlock, "effectBlock should be 0"); + _checkAllocation({ + allocation: allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock), + expectedCurrentMagnitude: deallocateParams[0].newMagnitudes[0], + expectedPendingDiff: 0, + expectedEffectBlock: 0 + }); } /** From f8fd730fe758cec20e9a1a73697162b47b569213 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:23:16 -0500 Subject: [PATCH 07/11] test(wip): todos --- src/test/unit/AllocationManagerUnit.t.sol | 367 ++++++++++++++++------ 1 file changed, 272 insertions(+), 95 deletions(-) diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index e8e55c71c..9a0ad0d83 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -160,7 +160,23 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag assertEq(expectedPendingDiff, allocation.pendingDiff, "pendingDiff != expected"); assertEq(expectedEffectBlock, allocation.effectBlock, "effectBlock != expected"); } - + + function _checkAllocationEvents( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy, + uint64 currentMagnitude, + uint64 encumberedMagnitude, + uint32 effectBlock + ) internal { + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit EncumberedMagnitudeUpdated(operator, strategy, encumberedMagnitude); + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit AllocationUpdated( + operator, operatorSet, strategy, currentMagnitude, effectBlock + ); + } + /// ----------------------------------------------------------------------- /// Allocate/deallocate params /// ----------------------------------------------------------------------- @@ -1283,25 +1299,87 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.modifyAllocations(allocateParams); } - function testFuzz_revert_insufficientAllocatableMagnitude( + function testFuzz_revert_overAllocate( Randomness r ) public rand(r) { - // Allocate some magnitude + uint8 numOpSets = uint8(r.Uint256(2, FUZZ_MAX_OP_SETS)); + + // Create and register for operator sets + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(operatorSets, defaultStrategies); + + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); + uint256 randIdx = r.Uint256(0, allocateParams.length - 1); + + allocateParams[randIdx].newMagnitudes[0] = WAD + 1; + + // Overallocate + cheats.expectRevert(InsufficientMagnitude.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + } + + function test_revert_allocateDeallocate_modificationPending() public { + // Allocate AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); - // Warp to allocation complete block + // Deallocate + allocateParams[0].newMagnitudes[0] -= 1; + cheats.expectRevert(ModificationAlreadyPending.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + } + + function test_revert_deallocateTwice_modificationPending() public { + // Allocate + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + + // Warp past allocation complete timestsamp cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); - // Attempt to allocate more magnitude than the operator has - // uint64 allocatedMag = allocateParams[0].newMagnitudes[0]; - allocateParams[0].newMagnitudes[0] = WAD + 1; - cheats.expectRevert(InsufficientMagnitude.selector); + // Deallocate + allocateParams[0].newMagnitudes[0] -= 1; + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(allocateParams); + + // Deallocate again -> expect revert + cheats.expectRevert(ModificationAlreadyPending.selector); cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); } + /// @dev Set allocation delay > ALLOCATION_CONFIGURATION_DELAY, allocate, + /// set allocation delay to < ALLOCATION_CONFIGURATION_DELAY, allocate again + /// once new delay is sect. + /// + /// NOTE: Should be able to allocate faster than `ALLOCATION_CONFIGURATION_DELAY`. + function testFuzz_ShouldBeAbleToAllocateSoonerThanLastDelay( + Randomness r + ) public rand(r) { + uint32 firstDelay = r.Uint32(ALLOCATION_CONFIGURATION_DELAY, type(uint24).max); + uint32 secondDelay = r.Uint32(1, ALLOCATION_CONFIGURATION_DELAY - 1); + uint64 half = 0.5 ether; + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(CreateSetParams(1, defaultStrategies).toArray()); + + cheats.startPrank(defaultOperator); + + allocationManager.setAllocationDelay(firstDelay); + + allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, half)); + + allocationManager.setAllocationDelay(secondDelay); + cheats.roll(block.number + secondDelay); + allocationManager.modifyAllocations(_newAllocateParams(OperatorSet(defaultAVS, 1), half)); + + cheats.stopPrank(); + } + function testFuzz_allocate_singleStrat_singleOperatorSet( Randomness r ) public rand(r) { @@ -1319,6 +1397,15 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe assertEq(allocatedSets.length, 0, "should not have any allocated sets before allocation"); assertEq(allocatedStrats.length, 0, "should not have any allocated strats before allocation"); + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: magnitude, + encumberedMagnitude: magnitude, + effectBlock: effectBlock + }); + // Allocate magnitude cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1366,12 +1453,11 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Create and register for operator sets, each with a single default strategy OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); + _createOperatorSets(operatorSets, defaultStrategies); _registerForOperatorSets(defaultOperator, operatorSets); - // Get a random allocation for the operator sets - AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); - // Save vars to check against uint32 effectBlock = uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); uint64 usedMagnitude; @@ -1386,6 +1472,17 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe assertEq(allocatedSets.length, 0, "should not have any allocated sets before allocation"); assertEq(allocatedStrats.length, 0, "should not have any allocated strats before allocation"); + for (uint256 i; i < allocateParams.length; ++i) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSets[i], + strategy: strategyMock, + currentMagnitude: allocateParams[i].newMagnitudes[0], + encumberedMagnitude: allocateParams[i].newMagnitudes[0], + effectBlock: effectBlock + }); + } + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1404,7 +1501,6 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocatedSets = allocationManager.getAllocatedSets(defaultOperator); assertEq(allocatedSets.length, numOpSets, "should have multiple allocated sets"); - Allocation memory allocation; for (uint256 i; i < allocateParams.length; ++i) { _checkAllocation({ allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), @@ -1444,6 +1540,15 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe assertEq(allocatedSets.length, 0, "should not have any allocated sets before allocation"); assertEq(allocatedStrats.length, 0, "should not have any allocated strats before allocation"); + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: firstAlloc, + encumberedMagnitude: firstAlloc, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + // Allocate magnitude AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstAlloc); cheats.prank(defaultOperator); @@ -1454,6 +1559,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Allocate magnitude again allocateParams = _newAllocateParams(defaultOperatorSet, secondAlloc); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: firstAlloc + secondAlloc, + encumberedMagnitude: firstAlloc + secondAlloc, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1472,26 +1587,6 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe assertEq(address(allocatedStrats[0]), address(strategyMock), "should have allocated default strat"); } - function testFuzz_revert_overAllocate( - Randomness r - ) public rand(r) { - uint8 numOpSets = uint8(r.Uint256(2, type(uint8).max)); - - // Create and register for operator sets - OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); - _createOperatorSets(operatorSets, defaultStrategies); - - AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); - uint256 randIdx = r.Uint256(0, allocateParams.length - 1); - - allocateParams[randIdx].newMagnitudes[0] = WAD + 1; - - // Overallocate - cheats.expectRevert(InsufficientMagnitude.selector); - cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); - } - function testFuzz_allocateMaxToMultipleStrategies( Randomness r ) public rand(r) { @@ -1502,6 +1597,17 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe _createOperatorSet(operatorSet, strategies); _registerForOperatorSet(defaultOperator, operatorSet); + + for (uint256 i; i < numStrats; ++i) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: strategies[i], + currentMagnitude: WAD, + encumberedMagnitude: WAD, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + } cheats.prank(defaultOperator); allocationManager.modifyAllocations( @@ -1518,39 +1624,6 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe } } - function test_revert_allocateDeallocate_modificationPending() public { - // Allocate - AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); - cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); - - // Deallocate - allocateParams[0].newMagnitudes[0] -= 1; - cheats.expectRevert(ModificationAlreadyPending.selector); - cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); - } - - function test_revert_deallocateTwice_modificationPending() public { - // Allocate - AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); - cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); - - // Warp past allocation complete timestsamp - cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); - - // Deallocate - allocateParams[0].newMagnitudes[0] -= 1; - cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); - - // Deallocate again -> expect revert - cheats.expectRevert(ModificationAlreadyPending.selector); - cheats.prank(defaultOperator); - allocationManager.modifyAllocations(allocateParams); - } - /** * Allocates to `firstMod` magnitude and then deallocate to `secondMod` magnitude * Validates the storage @@ -1567,6 +1640,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Allocate magnitude to default registered set AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstMod); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: firstMod, + encumberedMagnitude: firstMod, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1575,6 +1658,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Deallocate allocateParams = _newAllocateParams(defaultOperatorSet, secondMod); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: firstMod - secondMod, + encumberedMagnitude: firstMod - secondMod, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1638,6 +1731,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Allocate magnitude to operator set AllocateParams[] memory allocateParams = _newAllocateParams(operatorSetA, firstMod); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSetA, + strategy: strategyMock, + currentMagnitude: firstMod, + encumberedMagnitude: firstMod, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1655,6 +1758,23 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocateParams[0] = _newAllocateParams(operatorSetA, 0)[0]; allocateParams[1] = _newAllocateParams(operatorSetB, firstMod)[0]; + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSetA, + strategy: strategyMock, + currentMagnitude: 0, + encumberedMagnitude: 0, + effectBlock: 0 + }); + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSetB, + strategy: strategyMock, + currentMagnitude: firstMod, + encumberedMagnitude: firstMod, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1702,6 +1822,17 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe _registerForOperatorSets(defaultOperator, deallocSets); AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy_AllocAll(deallocSets); + for (uint256 i; i < numOpSets; ++i) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: deallocSets[i], + strategy: strategyMock, + currentMagnitude: WAD, + encumberedMagnitude: WAD, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + } + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1716,6 +1847,18 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Deallocate fully from each operator set AllocateParams[] memory deallocateParams = _newAllocateParams(deallocSets, 0); + + for (uint256 i; i < numOpSets; ++i) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: deallocSets[i], + strategy: strategyMock, + currentMagnitude: 0, + encumberedMagnitude: 0, + effectBlock: 0 + }); + } + cheats.prank(defaultOperator); allocationManager.modifyAllocations(deallocateParams); @@ -1742,6 +1885,15 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe _registerForOperatorSet(defaultOperator, finalOpSet); AllocateParams[] memory finalAllocParams = _newAllocateParams(finalOpSet, WAD); + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: finalOpSet, + strategy: strategyMock, + currentMagnitude: WAD, + encumberedMagnitude: WAD, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(finalAllocParams); @@ -1777,6 +1929,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe function test_deallocate_all() public { // Allocate AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: WAD, + encumberedMagnitude: WAD, + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1785,6 +1947,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe // Deallocate allocateParams[0].newMagnitudes[0] = 0; + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + currentMagnitude: 0, + encumberedMagnitude: 0, + effectBlock: 0 + }); + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); @@ -1820,6 +1992,17 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe _randAllocAndDeallocParams_SingleMockStrategy(operatorSets); // Allocate + for (uint256 i; i < allocateParams.length; ++i) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSets[i], + strategy: strategyMock, + currentMagnitude: allocateParams[i].newMagnitudes[0], + encumberedMagnitude: allocateParams[i].newMagnitudes[0], + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + } + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); uint64 encumberedMagnitudeAfterAllocation = allocationManager.encumberedMagnitude(defaultOperator, strategyMock); @@ -1832,7 +2015,16 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe uint64 postDeallocMag; for (uint256 i; i < deallocateParams.length; ++i) { postDeallocMag += deallocateParams[i].newMagnitudes[0]; + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSets[i], + strategy: strategyMock, + currentMagnitude: deallocateParams[i].newMagnitudes[0], + encumberedMagnitude: deallocateParams[i].newMagnitudes[0], + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); } + cheats.prank(defaultOperator); allocationManager.modifyAllocations(deallocateParams); @@ -1842,8 +2034,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.encumberedMagnitude(defaultOperator, strategyMock), "encumberedMagnitude should not be updated" ); - - Allocation memory allocation; + for (uint256 i; i < allocateParams.length; ++i) { _checkAllocation({ allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), @@ -1875,34 +2066,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe ); } - /// @dev Set allocation delay > ALLOCATION_CONFIGURATION_DELAY, allocate, - /// set allocation delay to < ALLOCATION_CONFIGURATION_DELAY, allocate again - /// once new delay is sect. - /// - /// NOTE: Should be able to allocate faster than `ALLOCATION_CONFIGURATION_DELAY`. - function testFuzz_modifyAllocations_ShouldBeAbleToAllocateSoonerThanLastDelay( - Randomness r - ) public rand(r) { - uint32 firstDelay = r.Uint32(ALLOCATION_CONFIGURATION_DELAY, type(uint24).max); - uint32 secondDelay = r.Uint32(1, ALLOCATION_CONFIGURATION_DELAY - 1); - uint64 half = 0.5 ether; - - cheats.prank(defaultAVS); - allocationManager.createOperatorSets(CreateSetParams(1, defaultStrategies).toArray()); - - cheats.startPrank(defaultOperator); - - allocationManager.setAllocationDelay(firstDelay); - allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, half)); - - allocationManager.setAllocationDelay(secondDelay); - cheats.roll(block.number + secondDelay); - allocationManager.modifyAllocations(_newAllocateParams(OperatorSet(defaultAVS, 1), half)); - - cheats.stopPrank(); - } - - function testFuzz_modifyAllocations_MultipleSetsAndStrats( + function testFuzz_MultipleSetsAndStrats( Randomness r ) public rand(r) { uint256 numAllocations = r.Uint256(2, FUZZ_MAX_ALLOCATIONS); @@ -1915,6 +2079,19 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe cheats.prank(defaultAVS); allocationManager.createOperatorSets(createSetParams); + for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 j; j < allocateParams[i].strategies.length; ++j) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: allocateParams[i].operatorSet, + strategy: allocateParams[i].strategies[j], + currentMagnitude: allocateParams[i].newMagnitudes[j], + encumberedMagnitude: allocateParams[i].newMagnitudes[j], + effectBlock: uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY) + }); + } + } + cheats.prank(defaultOperator); allocationManager.modifyAllocations(allocateParams); From f81ab084f0380d2954015a9f3d86743c36b3c053 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:39:08 -0500 Subject: [PATCH 08/11] test(wip): todos --- src/test/unit/AllocationManagerUnit.t.sol | 123 ++++++++++++++++++++-- src/test/utils/SingleItemArrayLib.sol | 18 ++++ 2 files changed, 132 insertions(+), 9 deletions(-) diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index 9a0ad0d83..b46d3c143 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -160,7 +160,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag assertEq(expectedPendingDiff, allocation.pendingDiff, "pendingDiff != expected"); assertEq(expectedEffectBlock, allocation.effectBlock, "effectBlock != expected"); } - + function _checkAllocationEvents( address operator, OperatorSet memory operatorSet, @@ -172,11 +172,20 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag cheats.expectEmit(true, false, false, false, address(allocationManager)); emit EncumberedMagnitudeUpdated(operator, strategy, encumberedMagnitude); cheats.expectEmit(true, false, false, false, address(allocationManager)); - emit AllocationUpdated( - operator, operatorSet, strategy, currentMagnitude, effectBlock - ); + emit AllocationUpdated(operator, operatorSet, strategy, currentMagnitude, effectBlock); + } + + function _checkSlashEvents( + address operator, + OperatorSet memory operatorSet, + IStrategy[] memory strategies, + uint256[] memory wadToSlash, + string memory description + ) internal { + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit OperatorSlashed(operator, operatorSet, strategies, wadToSlash, description); } - + /// ----------------------------------------------------------------------- /// Allocate/deallocate params /// ----------------------------------------------------------------------- @@ -455,6 +464,8 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.modifyAllocations(allocateParams); cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + _checkSlashEvents(defaultOperator, defaultOperatorSet, defaultStrategies, uint256(25e16).toArrayU256(), "test"); + // Slash operator for 25% cheats.prank(defaultAVS); allocationManager.slashOperator( @@ -506,6 +517,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint64 expectedEncumberedMagnitude = allocateParams[0].newMagnitudes[0] - expectedSlashedMagnitude; uint64 maxMagnitudeAfterSlash = WAD - expectedSlashedMagnitude; + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(expectedSlashedMagnitude).toArrayU256(), + description: "test" + }); + // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -564,6 +583,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint64 magnitudeAfterSlash = 25e16; uint64 maxMagnitudeAfterSlash = 75e16; + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(50e16).toArrayU256(), + description: "test" + }); + // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -636,6 +663,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint64 magnitudeAfterSlash = 1e16; uint64 maxMagnitudeAfterSlash = 1e16; // 1e15 is maxMagnitude + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(99e16).toArrayU256(), + description: "test" + }); + // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -666,6 +701,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests magnitudeAfterSlash = 1e12; maxMagnitudeAfterSlash = 1e12; + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(9999e14).toArrayU256(), + description: "test" + }); + cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -696,6 +739,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests magnitudeAfterSlash = 0; maxMagnitudeAfterSlash = 0; + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(WAD - 1e3).toArrayU256(), + description: "test" + }); + // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -753,6 +804,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint64 magnitudeAfterSlash = 75e16; uint64 maxMagnitudeAfterSlash = 75e16; // Operator can only allocate up to 75e16 magnitude since 25% is slashed + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(25e16).toArrayU256(), + description: "test" + }); + // Slash Operator // First event is emitted because of deallocation cheats.prank(defaultAVS); @@ -807,6 +866,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests allocationManager.modifyAllocations(allocateParams); cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: WAD.toArrayU256(), + description: "test" + }); + // Slash operator for 100% cheats.prank(defaultAVS); allocationManager.slashOperator( @@ -844,6 +911,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests cheats.prank(defaultOperator); allocationManager.modifyAllocations(_newAllocateParams(defaultOperatorSet, 0)); + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: WAD.toArrayU256(), + description: "test" + }); + // Slash operator for 100% cheats.prank(defaultAVS); allocationManager.slashOperator( @@ -911,6 +986,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint64 magnitudeAfterSlash = 375e15; uint64 maxMagnitudeAfterSlash = 875e15; // Operator can only allocate up to 75e16 magnitude since 25% is slashed + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(25e16).toArrayU256(), + description: "test" + }); + // Slash Operator, only emit events assuming that there is no deallocation cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -1001,6 +1084,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests description: "test" }); + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategies: defaultStrategies, + wadToSlash: uint256(5e17).toArrayU256(), + description: "test" + }); + // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -1094,6 +1185,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests expectedMaxMagnitudeAfterSlash[0] = 7e17; expectedMaxMagnitudeAfterSlash[1] = 4e17; + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategies: strategies, + wadToSlash: uint256(6e17).toArrayU256(), + description: "test" + }); + // Slash Operator cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -1155,6 +1254,14 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests uint256 currentMagnitude = magnitudeBeforeSlash - slashedMagnitude - 1; uint256 maxMagnitude = WAD - slashedMagnitude - 1; + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategies: strategy.toArray(), + wadToSlash: uint256(slashingParams.wadToSlash).toArrayU256(), + description: "test" + }); + cheats.prank(defaultAVS); allocationManager.slashOperator(slashingParams); @@ -1597,7 +1704,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe _createOperatorSet(operatorSet, strategies); _registerForOperatorSet(defaultOperator, operatorSet); - + for (uint256 i; i < numStrats; ++i) { _checkAllocationEvents({ operator: defaultOperator, @@ -2034,7 +2141,7 @@ contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTe allocationManager.encumberedMagnitude(defaultOperator, strategyMock), "encumberedMagnitude should not be updated" ); - + for (uint256 i; i < allocateParams.length; ++i) { _checkAllocation({ allocation: allocationManager.getAllocation(defaultOperator, operatorSets[i], strategyMock), @@ -2294,7 +2401,6 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU allocationManager.modifyAllocations(secondAllocation); allocation = allocationManager.getAllocation(defaultOperator, newOperatorSet, strategyMock); assertEq(allocationEffectBlock, allocation.effectBlock, "effect block not correct"); - assertLt(allocationEffectBlock, deallocationEffectBlock, "invalid test setup"); // Warp to allocation effect block & clear the queue cheats.roll(allocationEffectBlock); @@ -2356,7 +2462,6 @@ contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerU allocationManager.modifyAllocations(firstDeallocation); allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); assertEq(deallocationEffectBlock, allocation.effectBlock, "effect block not correct"); - assertLt(deallocationEffectBlock, allocationEffectBlock, "invalid test setup"); // Warp to deallocation effect block & clear the queue cheats.roll(deallocationEffectBlock); diff --git a/src/test/utils/SingleItemArrayLib.sol b/src/test/utils/SingleItemArrayLib.sol index 61ace04fe..b864e5b9e 100644 --- a/src/test/utils/SingleItemArrayLib.sol +++ b/src/test/utils/SingleItemArrayLib.sol @@ -30,6 +30,14 @@ library SingleItemArrayLib { array[0] = x; } + function toArrayU256( + uint256 x + ) internal pure returns (uint256[] memory array) { + array = new uint256[](1); + array[0] = x; + } + + function toArrayU16( uint16 x, uint256 len @@ -60,6 +68,16 @@ library SingleItemArrayLib { } } + function toArrayU256( + uint256 x, + uint256 len + ) internal pure returns (uint256[] memory array) { + array = new uint256[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + function toArray( IStrategy strategy ) internal pure returns (IStrategy[] memory array) { From e0658eefdb7736acba90e7523c3ccc2d728cc130 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Fri, 8 Nov 2024 10:23:23 -0500 Subject: [PATCH 09/11] fix: cherry-pick errors --- src/test/unit/AllocationManagerUnit.t.sol | 2 -- src/test/unit/DelegationUnit.t.sol | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index b46d3c143..08162b783 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -5,8 +5,6 @@ import "src/contracts/core/AllocationManager.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; import "src/test/mocks/MockAVSRegistrar.sol"; -// TODO: Add **unique** tests for events. - contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManagerErrors, IAllocationManagerEvents { using SingleItemArrayLib for *; diff --git a/src/test/unit/DelegationUnit.t.sol b/src/test/unit/DelegationUnit.t.sol index 6cadbd14a..6be226502 100644 --- a/src/test/unit/DelegationUnit.t.sol +++ b/src/test/unit/DelegationUnit.t.sol @@ -2771,9 +2771,6 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { (uint256 depositScalingFactor,,) = delegationManager.stakerScalingFactor(defaultStaker, strategyMock); assertEq(depositScalingFactor, WAD, "bad test setup"); - - // Get withdrawable shares - (, uint256[] memory depositShares) = delegationManager.getWithdrawableShares(defaultStaker, strategies); // Format queued withdrawal ( @@ -2913,7 +2910,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // Format queued withdrawal ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + , IDelegationManagerTypes.Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ From c54e27b09bda68d49db8fbe5ebcde667fe631c8b Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Fri, 8 Nov 2024 10:30:22 -0500 Subject: [PATCH 10/11] fix: forge-std --- lib/forge-std | 1 + 1 file changed, 1 insertion(+) create mode 160000 lib/forge-std diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 000000000..4f57c59f0 --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 4f57c59f066a03d13de8c65bb34fca8247f5fcb2 From e518206a61fa69d7f26c09ad703f3dedc84e1be0 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:13:06 -0500 Subject: [PATCH 11/11] test(wip): todos --- src/test/unit/DelegationUnit.t.sol | 695 +++++++++++++------------- src/test/utils/Random.sol | 6 + src/test/utils/SingleItemArrayLib.sol | 15 +- 3 files changed, 358 insertions(+), 358 deletions(-) diff --git a/src/test/unit/DelegationUnit.t.sol b/src/test/unit/DelegationUnit.t.sol index 6be226502..ee54ba2ae 100644 --- a/src/test/unit/DelegationUnit.t.sol +++ b/src/test/unit/DelegationUnit.t.sol @@ -8,6 +8,10 @@ import "src/contracts/core/DelegationManager.sol"; import "src/contracts/strategies/StrategyBase.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; import "src/contracts/libraries/SlashingLib.sol"; +import "src/test/utils/SingleItemArrayLib.sol"; + +// TODO: add upgrade tests for completing withdrawals queued before upgrade in integration tests +// TODO: add slashing cases for withdrawing as shares (can also be in integration tests) /** * @notice Unit testing of the DelegationManager contract. Withdrawals are tightly coupled @@ -15,8 +19,9 @@ import "src/contracts/libraries/SlashingLib.sol"; * Contracts tested: DelegationManager * Contracts not mocked: StrategyBase, PauserRegistry */ -contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManagerEvents { - using SlashingLib for *; +contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManagerEvents, IDelegationManagerErrors { + using SlashingLib for *; + using SingleItemArrayLib for *; // Contract under test DelegationManager delegationManager; @@ -29,8 +34,8 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag StrategyBase strategyImplementation; StrategyBase strategyMock; - IERC20 mockToken; - uint256 mockTokenInitialSupply = 10e50; + IERC20 tokenMock; + uint256 tokenMockInitialSupply = 10e50; uint32 constant MIN_WITHDRAWAL_DELAY_BLOCKS = 126_000; // 17.5 days in blocks @@ -104,14 +109,14 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag ); // Deploy mock token and strategy - mockToken = new ERC20PresetFixedSupply("Mock Token", "MOCK", mockTokenInitialSupply, address(this)); + tokenMock = new ERC20PresetFixedSupply("Mock Token", "MOCK", tokenMockInitialSupply, address(this)); strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyMock = StrategyBase( address( new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, mockToken) + abi.encodeWithSelector(StrategyBase.initialize.selector, tokenMock) ) ) ); @@ -143,7 +148,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag ERC20PresetFixedSupply token = new ERC20PresetFixedSupply( string(abi.encodePacked("Mock Token ", i)), string(abi.encodePacked("MOCK", i)), - mockTokenInitialSupply, + tokenMockInitialSupply, address(this) ); strategies[i] = StrategyBase( @@ -212,7 +217,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag } function _registerOperatorWithBaseDetails(address operator) internal { - IDelegationManagerTypes.OperatorDetails memory operatorDetails = IDelegationManagerTypes.OperatorDetails({ + OperatorDetails memory operatorDetails = OperatorDetails({ __deprecated_earningsReceiver: operator, delegationApprover: address(0), __deprecated_stakerOptOutWindowBlocks: 0 @@ -221,7 +226,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag } function _registerOperatorWithDelegationApprover(address operator) internal { - IDelegationManagerTypes.OperatorDetails memory operatorDetails = IDelegationManagerTypes.OperatorDetails({ + OperatorDetails memory operatorDetails = OperatorDetails({ __deprecated_earningsReceiver: operator, delegationApprover: defaultApprover, __deprecated_stakerOptOutWindowBlocks: 0 @@ -237,7 +242,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag */ ERC1271WalletMock wallet = new ERC1271WalletMock(delegationSigner); - IDelegationManagerTypes.OperatorDetails memory operatorDetails = IDelegationManagerTypes.OperatorDetails({ + OperatorDetails memory operatorDetails = OperatorDetails({ __deprecated_earningsReceiver: operator, delegationApprover: address(wallet), __deprecated_stakerOptOutWindowBlocks: 0 @@ -249,7 +254,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag function _registerOperator( address operator, - IDelegationManagerTypes.OperatorDetails memory operatorDetails, + OperatorDetails memory operatorDetails, string memory metadataURI ) internal filterFuzzedAddressInputs(operator) { cheats.prank(operator); @@ -280,18 +285,15 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag IStrategy strategy, uint256 depositSharesToWithdraw ) internal view returns ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory, - IDelegationManagerTypes.Withdrawal memory, + QueuedWithdrawalParams[] memory, + Withdrawal memory, bytes32 ) { - IStrategy[] memory strategyArray = new IStrategy[](1); - strategyArray[0] = strategy; - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); + IStrategy[] memory strategyArray = strategy.toArray(); + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); { - uint256[] memory withdrawalAmounts = new uint256[](1); - withdrawalAmounts[0] = depositSharesToWithdraw; - - queuedWithdrawalParams[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + uint256[] memory withdrawalAmounts = depositSharesToWithdraw.toArrayU256(); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ strategies: strategyArray, depositShares: withdrawalAmounts, withdrawer: withdrawer @@ -299,10 +301,9 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag } // Get scaled shares to withdraw - uint256[] memory scaledSharesArray = new uint256[](1); - scaledSharesArray[0] = _getScaledShares(staker, strategy, depositSharesToWithdraw); + uint256[] memory scaledSharesArray = _getScaledShares(staker, strategy, depositSharesToWithdraw).toArrayU256(); - IDelegationManagerTypes.Withdrawal memory withdrawal = IDelegationManagerTypes.Withdrawal({ + Withdrawal memory withdrawal = Withdrawal({ staker: staker, delegatedTo: delegationManager.delegatedTo(staker), withdrawer: withdrawer, @@ -322,13 +323,13 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag IStrategy[] memory strategies, uint256[] memory depositWithdrawalAmounts ) internal view returns ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory, - IDelegationManagerTypes.Withdrawal memory, + QueuedWithdrawalParams[] memory, + Withdrawal memory, bytes32 ) { - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); { - queuedWithdrawalParams[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ strategies: strategies, depositShares: depositWithdrawalAmounts, withdrawer: withdrawer @@ -341,7 +342,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag scaledSharesArray[i] = _getScaledShares(staker, strategies[i], depositWithdrawalAmounts[i]); } - IDelegationManagerTypes.Withdrawal memory withdrawal = IDelegationManagerTypes.Withdrawal({ + Withdrawal memory withdrawal = Withdrawal({ staker: staker, delegatedTo: delegationManager.delegatedTo(staker), withdrawer: withdrawer, @@ -358,9 +359,6 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag function _getScaledShares(address staker, IStrategy strategy, uint256 depositSharesToWithdraw) internal view returns (uint256) { // Setup vars address operator = delegationManager.delegatedTo(staker); - IStrategy[] memory strategyArray = new IStrategy[](1); - strategyArray[0] = strategy; - // Set scaling factors (uint184 depositScalingFactor, uint64 beaconChainScalingFactor, bool isBeaconChainScalingFactorSet) = delegationManager.stakerScalingFactor(staker, strategy); StakerScalingFactors memory stakerScalingFactor = StakerScalingFactors({ @@ -369,7 +367,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag beaconChainScalingFactor: beaconChainScalingFactor }); - uint64 maxMagnitude = allocationManagerMock.getMaxMagnitudes(operator, strategyArray)[0]; + uint64 maxMagnitude = allocationManagerMock.getMaxMagnitudes(operator, strategy.toArray())[0]; uint256 sharesToWithdraw = depositSharesToWithdraw.toShares(stakerScalingFactor, maxMagnitude); uint256 scaledShares = SlashingLib.scaleSharesForQueuedWithdrawal( @@ -392,13 +390,12 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address withdrawer, uint256 depositAmount, uint256 withdrawalAmount - ) internal returns (IDelegationManagerTypes.Withdrawal memory, IERC20[] memory, bytes32) { - uint256[] memory depositAmounts = new uint256[](1); - depositAmounts[0] = depositAmount; + ) internal returns (Withdrawal memory, IERC20[] memory, bytes32) { + uint256[] memory depositAmounts = depositAmount.toArrayU256(); IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: staker, @@ -410,12 +407,10 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag cheats.prank(staker); delegationManager.queueWithdrawals(queuedWithdrawalParams); // Set the current deposits to be the depositAmount - withdrawalAmount - uint256[] memory currentAmounts = new uint256[](1); - currentAmounts[0] = depositAmount - withdrawalAmount; + uint256[] memory currentAmounts = uint256(depositAmount - withdrawalAmount).toArrayU256(); strategyManagerMock.setDeposits(staker, strategies, currentAmounts); IERC20[] memory tokens = new IERC20[](strategies.length); - for (uint i = 0; i < tokens.length; i++) { tokens[i] = strategies[i].underlyingToken(); } @@ -434,7 +429,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address withdrawer, uint256[] memory depositAmounts, uint256[] memory withdrawalAmounts - ) internal returns (IDelegationManagerTypes.Withdrawal memory, IERC20[] memory, bytes32) { + ) internal returns (Withdrawal memory, IERC20[] memory, bytes32) { IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); IERC20[] memory tokens = new IERC20[](strategies.length); @@ -443,8 +438,8 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag } ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawals({ staker: staker, @@ -510,7 +505,7 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU cheats.expectRevert(IPausable.CurrentlyPaused.selector); delegationManager.registerAsOperator( - IDelegationManagerTypes.OperatorDetails({ + OperatorDetails({ __deprecated_earningsReceiver: defaultOperator, delegationApprover: address(0), __deprecated_stakerOptOutWindowBlocks: 0 @@ -522,14 +517,14 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU // @notice Verifies that someone cannot successfully call `DelegationManager.registerAsOperator(operatorDetails)` again after registering for the first time function testFuzz_registerAsOperator_revert_cannotRegisterMultipleTimes( - IDelegationManagerTypes.OperatorDetails memory operatorDetails + OperatorDetails memory operatorDetails ) public { // Register once cheats.startPrank(defaultOperator); delegationManager.registerAsOperator(operatorDetails, 0, emptyStringForMetadataURI); // Expect revert when register again - cheats.expectRevert(IDelegationManagerErrors.ActivelyDelegated.selector); + cheats.expectRevert(ActivelyDelegated.selector); delegationManager.registerAsOperator(operatorDetails, 0, emptyStringForMetadataURI); cheats.stopPrank(); } @@ -545,7 +540,7 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU */ function testFuzz_registerAsOperator( address operator, - IDelegationManagerTypes.OperatorDetails memory operatorDetails, + OperatorDetails memory operatorDetails, string memory metadataURI ) public filterFuzzedAddressInputs(operator) { cheats.expectEmit(true, true, true, true, address(delegationManager)); @@ -575,7 +570,7 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU // @notice Verifies that a staker who is actively delegated to an operator cannot register as an operator (without first undelegating, at least) function testFuzz_Revert_registerAsOperator_cannotRegisterWhileDelegated( address staker, - IDelegationManagerTypes.OperatorDetails memory operatorDetails + OperatorDetails memory operatorDetails ) public filterFuzzedAddressInputs(staker) { cheats.assume(staker != defaultOperator); @@ -588,7 +583,7 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); // expect revert if attempt to register as operator - cheats.expectRevert(IDelegationManagerErrors.ActivelyDelegated.selector); + cheats.expectRevert(ActivelyDelegated.selector); delegationManager.registerAsOperator(operatorDetails, 0, emptyStringForMetadataURI); cheats.stopPrank(); @@ -616,8 +611,8 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU * @param initialOperatorDetails and @param modifiedOperatorDetails are fuzzed inputs */ function testFuzz_modifyOperatorParameters( - IDelegationManagerTypes.OperatorDetails memory initialOperatorDetails, - IDelegationManagerTypes.OperatorDetails memory modifiedOperatorDetails + OperatorDetails memory initialOperatorDetails, + OperatorDetails memory modifiedOperatorDetails ) public { _registerOperator(defaultOperator, initialOperatorDetails, emptyStringForMetadataURI); @@ -643,7 +638,7 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU assertFalse(delegationManager.isOperator(defaultOperator), "bad test setup"); cheats.prank(defaultOperator); - cheats.expectRevert(IDelegationManagerErrors.OperatorNotRegistered.selector); + cheats.expectRevert(OperatorNotRegistered.selector); delegationManager.updateOperatorMetadataURI(emptyStringForMetadataURI); } @@ -653,9 +648,9 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU * invariant that 'operators' are always delegated to themselves */ function testFuzz_Revert_updateOperatorMetadataUri_notOperator( - IDelegationManagerTypes.OperatorDetails memory operatorDetails + OperatorDetails memory operatorDetails ) public { - cheats.expectRevert(IDelegationManagerErrors.OperatorNotRegistered.selector); + cheats.expectRevert(OperatorNotRegistered.selector); delegationManager.modifyOperatorDetails(operatorDetails); } @@ -673,10 +668,12 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU } contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + function test_Revert_WhenPaused() public { cheats.prank(defaultOperator); delegationManager.registerAsOperator( - IDelegationManagerTypes.OperatorDetails({ + OperatorDetails({ __deprecated_earningsReceiver: defaultOperator, delegationApprover: address(0), __deprecated_stakerOptOutWindowBlocks: 0 @@ -714,7 +711,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate again and check that the call reverts cheats.prank(staker); - cheats.expectRevert(IDelegationManagerErrors.ActivelyDelegated.selector); + cheats.expectRevert(ActivelyDelegated.selector); delegationManager.delegateTo(operator, approverSignatureAndExpiry, salt); } @@ -727,7 +724,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate and check that the call reverts cheats.prank(staker); - cheats.expectRevert(IDelegationManagerErrors.OperatorNotRegistered.selector); + cheats.expectRevert(OperatorNotRegistered.selector); ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; delegationManager.delegateTo(operator, approverSignatureAndExpiry, emptySalt); } @@ -762,10 +759,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // Set staker shares in StrategyManager - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); // delegate from the `staker` to the operator @@ -812,10 +807,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperatorWithBaseDetails(defaultOperator); // Set staker shares in StrategyManager - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); // Set the operators magnitude to be 0 @@ -823,7 +816,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // delegate from the `staker` to the operator cheats.prank(staker); - cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(FullySlashed.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); assertTrue(delegationManager.delegatedTo(staker) != defaultOperator, "staker should not be delegated to the operator"); @@ -877,7 +870,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(FullySlashed.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); @@ -916,10 +909,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperatorWithBaseDetails(defaultOperator); // Set staker shares in StrategyManager - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); @@ -1085,8 +1076,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = beaconChainETHStrategy; + IStrategy[] memory strategiesToReturn = beaconChainETHStrategy.toArray(); (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); if (beaconShares > 0) { assertEq(withdrawableShares[0], uint256(beaconShares), "staker shares not set correctly"); @@ -1122,10 +1112,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // Set staker shares in BeaconChainStrategy and StrategyMananger - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); @@ -1197,10 +1185,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _setOperatorMagnitude(defaultOperator, strategyMock, 5e17); // Set staker shares in BeaconChainStrategy and StrategyMananger - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); @@ -1393,7 +1379,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent not spent?" ); delegationManager.undelegate(staker); - cheats.expectRevert(IDelegationManagerErrors.SaltSpent.selector); + cheats.expectRevert(SaltSpent.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -1547,10 +1533,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { ); // Set staker shares in StrategyManager - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); // delegate from the `staker` to the operator @@ -1722,10 +1706,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // Set staker shares in BeaconChainStrategy and StrategyMananger { - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); } @@ -1846,7 +1828,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); delegationManager.undelegate(staker); // Reusing same signature should revert with salt already being used - cheats.expectRevert(IDelegationManagerErrors.SaltSpent.selector); + cheats.expectRevert(SaltSpent.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -1873,7 +1855,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // then we don't even trigger the signature verification call, so we won't get a revert as expected cheats.assume(staker != address(wallet)); - IDelegationManagerTypes.OperatorDetails memory operatorDetails = IDelegationManagerTypes.OperatorDetails({ + OperatorDetails memory operatorDetails = OperatorDetails({ __deprecated_earningsReceiver: defaultOperator, delegationApprover: address(wallet), __deprecated_stakerOptOutWindowBlocks: 0 @@ -1916,7 +1898,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // then we don't even trigger the signature verification call, so we won't get a revert as expected cheats.assume(staker != address(wallet)); - IDelegationManagerTypes.OperatorDetails memory operatorDetails = IDelegationManagerTypes.OperatorDetails({ + OperatorDetails memory operatorDetails = OperatorDetails({ __deprecated_earningsReceiver: defaultOperator, delegationApprover: address(wallet), __deprecated_stakerOptOutWindowBlocks: 0 @@ -2017,6 +1999,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { } contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + // @notice Verifies that `DelegationManager.increaseDelegatedShares` reverts if not called by the StrategyManager nor EigenPodManager function testFuzz_increaseDelegatedShares_revert_invalidCaller( address invalidCaller, @@ -2026,7 +2010,7 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest cheats.assume(invalidCaller != address(eigenPodManagerMock)); cheats.assume(invalidCaller != address(eigenLayerProxyAdmin)); - cheats.expectRevert(IDelegationManagerErrors.OnlyStrategyManagerOrEigenPodManager.selector); + cheats.expectRevert(OnlyStrategyManagerOrEigenPodManager.selector); delegationManager.increaseDelegatedShares(invalidCaller, strategyMock, 0, shares); } @@ -2180,7 +2164,7 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest ); cheats.prank(address(strategyManagerMock)); - cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(FullySlashed.selector); delegationManager.increaseDelegatedShares(staker, strategyMock, 0, shares); uint256 delegatedSharesAfter = delegationManager.operatorShares( @@ -2220,10 +2204,8 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest // 2. set staker initial shares and increase delegated shares cheats.prank(address(strategyManagerMock)); delegationManager.increaseDelegatedShares(staker, strategyMock, 0, existingShares); - IStrategy[] memory strategiesDeposited = new IStrategy[](1); - strategiesDeposited[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = existingShares; + IStrategy[] memory strategiesDeposited = strategyMock.toArray(); + uint256[] memory sharesToReturn = existingShares.toArrayU256(); strategyManagerMock.setDeposits(staker, strategiesDeposited, sharesToReturn); (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesDeposited); if (existingShares < 1e18) { @@ -2253,7 +2235,7 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest // 4. Try to "redeposit" and expect a revert since strategy is 100% slashed // staker's withdrawable shares should also be 0 now cheats.prank(address(strategyManagerMock)); - cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(FullySlashed.selector); delegationManager.increaseDelegatedShares(staker, strategyMock, existingShares, shares); (withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesDeposited); @@ -2329,7 +2311,7 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest cheats.assume(invalidCaller != address(allocationManagerMock)); cheats.startPrank(invalidCaller); - cheats.expectRevert(IDelegationManagerErrors.OnlyAllocationManager.selector); + cheats.expectRevert(OnlyAllocationManager.selector); delegationManager.decreaseOperatorShares(invalidCaller, strategyMock, 0); } @@ -2349,22 +2331,20 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest * TODO: fuzz magnitude */ function testFuzz_decreaseOperatorShares_slashedOperator( - IStrategy[] memory strategies, - uint128 shares, - bool delegateFromStakerToOperator - ) public { - // sanity-filtering on fuzzed input length & staker - cheats.assume(strategies.length <= 16); - // TODO: remove, handles rounding on division - cheats.assume(shares % 2 == 0); + Randomness r + ) public rand(r) { + uint256 numStrats = r.Uint256(1, 16); + IStrategy[] memory strategies = r.StrategyArray(16); + uint128 shares = r.Uint128(); + bool delegateFromStakerToOperator = r.Boolean(); bool hasBeaconChainStrategy = false; - for(uint256 i = 0; i < strategies.length; i++) { + for(uint256 i = 0; i < numStrats; i++) { if (strategies[i] == beaconChainETHStrategy) { hasBeaconChainStrategy = true; // Swap beacon chain strategy to the end of the array - strategies[i] = strategies[strategies.length - 1]; - strategies[strategies.length - 1] = beaconChainETHStrategy; + strategies[i] = strategies[numStrats - 1]; + strategies[numStrats - 1] = beaconChainETHStrategy; // Resize assembly { @@ -2462,6 +2442,7 @@ contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTest contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { using SlashingLib for uint256; + using SingleItemArrayLib for *; // @notice Verifies that undelegating is not possible when the "undelegation paused" switch is flipped function test_undelegate_revert_paused(address staker) public filterFuzzedAddressInputs(staker) { @@ -2481,7 +2462,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { assertFalse(delegationManager.isDelegated(undelegatedStaker), "bad test setup"); cheats.prank(undelegatedStaker); - cheats.expectRevert(IDelegationManagerErrors.NotActivelyDelegated.selector); + cheats.expectRevert(NotActivelyDelegated.selector); delegationManager.undelegate(undelegatedStaker); } @@ -2490,7 +2471,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { _registerOperatorWithBaseDetails(operator); cheats.prank(operator); - cheats.expectRevert(IDelegationManagerErrors.OperatorsCannotUndelegate.selector); + cheats.expectRevert(OperatorsCannotUndelegate.selector); delegationManager.undelegate(operator); } @@ -2514,7 +2495,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // try to call the `undelegate` function and check for reversion cheats.prank(caller); - cheats.expectRevert(IDelegationManagerErrors.OperatorsCannotUndelegate.selector); + cheats.expectRevert(OperatorsCannotUndelegate.selector); delegationManager.undelegate(defaultOperator); } @@ -2544,7 +2525,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { _delegateToOperatorWhoRequiresSig(staker, defaultOperator); cheats.prank(invalidCaller); - cheats.expectRevert(IDelegationManagerErrors.CallerCannotUndelegate.selector); + cheats.expectRevert(CallerCannotUndelegate.selector); delegationManager.undelegate(staker); } @@ -2617,10 +2598,8 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { */ function testFuzz_undelegate_nonSlashedOperator(uint128 shares) public { // Set the staker deposits in the strategies - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = shares; + IStrategy[] memory strategies = strategyMock.toArray(); + uint256[] memory sharesToSet = shares.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); // register *this contract* as an operator and delegate from the `staker` to them @@ -2629,8 +2608,8 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // Format queued withdrawal ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -2670,9 +2649,8 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { * @notice The operator should have its shares slashed prior to the staker's deposit * TODO: fuzz magnitude */ - function testFuzz_undelegate_preSlashedOperator(uint128 shares) public { - // TODO: remove this assumption & properly handle rounding on division - cheats.assume(shares % 2 == 0); + function testFuzz_undelegate_preSlashedOperator(Randomness r) public rand(r) { + uint128 shares = r.Uint128(); uint64 operatorMagnitude = 5e17; // register *this contract* as an operator & set its slashed magnitude @@ -2680,11 +2658,9 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { _setOperatorMagnitude(defaultOperator, strategyMock, operatorMagnitude); // Set the staker deposits in the strategies - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = shares; + uint256[] memory sharesToSet = shares.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); } @@ -2695,8 +2671,8 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // Format queued withdrawal ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -2738,19 +2714,19 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { * @notice The operator should have its shares slashed prior to the staker's deposit * TODO: fuzz magnitude */ - function testFuzz_undelegate_slashedWhileStaked(uint128 shares) public { - // TODO: remove this assumption & properly handle rounding on division + function testFuzz_undelegate_slashedWhileStaked(Randomness r) public rand(r) { + uint128 shares = r.Uint128(); + + // TODO remove this assumption cheats.assume(shares % 2 == 0); // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); // Set the staker deposits in the strategies - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = shares; + uint256[] memory sharesToSet = shares.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); } @@ -2775,7 +2751,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // Format queued withdrawal ( , - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -2784,9 +2760,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { depositSharesToWithdraw: shares }); - uint256[] memory sharesToWithdraw = new uint256[](1); - sharesToWithdraw[0] = shares / 2; - + uint256[] memory sharesToWithdraw = uint256(shares / 2).toArrayU256(); // Undelegate the staker cheats.expectEmit(true, true, true, true, address(delegationManager)); emit StakerUndelegated(defaultStaker, defaultOperator); @@ -2824,11 +2798,9 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { _registerOperatorWithBaseDetails(defaultOperator); // Set the staker deposits in the strategies - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = shares; + uint256[] memory sharesToSet = shares.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); } @@ -2894,11 +2866,9 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { _setOperatorMagnitude(defaultOperator, strategyMock, operatorMagnitude); // Set the staker deposits in the strategies - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = shares; + uint256[] memory sharesToSet = shares.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); } @@ -2911,7 +2881,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // Format queued withdrawal ( , - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -2927,10 +2897,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { }); uint256 operatorSharesDecreased = uint256(shares).toShares(ssf, operatorMagnitude); - - uint256[] memory sharesToWithdraw = new uint256[](1); - sharesToWithdraw[0] = operatorSharesDecreased; - + uint256[] memory sharesToWithdraw = operatorSharesDecreased.toArrayU256(); // Undelegate the staker cheats.expectEmit(true, true, true, true, address(delegationManager)); emit StakerUndelegated(defaultStaker, defaultOperator); @@ -2970,23 +2937,23 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { assertLe(operatorSharesAfter, operatorSharesBefore, "operator shares should be less than or equal to before due to potential rounding"); } - // TODO: fix old Withdrawals.t.sol test - // // @notice This function tests to ensure that a delegator can re-delegate to an operator after undelegating. + // // TODO: fix old Withdrawals.t.sol test + // // @notice This function tests to ensure that a delegator can re-delegate to an operator after undelegating. // // @param operator is the operator being delegated to. // // @param staker is the staker delegating stake to the operator. - // function testRedelegateAfterWithdrawal( - // address operator, - // address depositor, - // uint96 ethAmount, - // uint96 eigenAmount, - // bool withdrawAsShares - // ) public fuzzedAddress(operator) fuzzedAddress(depositor) { - // cheats.assume(depositor != operator); + // function testFuzz_RedelegateAfterWithdrawal( + // Randomness r + // ) public rand(r) { + // address operator = r.Address(); + // address depositor = r.Address(); + // uint96 ethAmount = r.Uint96(); + // uint96 eigenAmount = r.Uint96(); + // bool withdrawAsShares = r.Boolean(); // //this function performs delegation and subsequent withdrawal // testWithdrawalWrapper(operator, depositor, ethAmount, eigenAmount, withdrawAsShares, true); // cheats.prank(depositor); - // delegation.undelegate(depositor); + // delegationManager.undelegate(depositor); // //warps past fraudproof time interval // cheats.warp(block.timestamp + 7 days + 1); @@ -2996,11 +2963,12 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTests { using SlashingLib for *; + using SingleItemArrayLib for *; function test_Revert_WhenEnterQueueWithdrawalsPaused() public { cheats.prank(pauser); delegationManager.pause(2 ** PAUSED_ENTER_WITHDRAWAL_QUEUE); - (IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ + (QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, withdrawer: defaultStaker, strategy: strategyMock, @@ -3011,33 +2979,32 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes } function test_Revert_WhenQueueWithdrawalParamsLengthMismatch() public { - IStrategy[] memory strategyArray = new IStrategy[](1); - strategyArray[0] = strategyMock; + IStrategy[] memory strategyArray = strategyMock.toArray(); uint256[] memory shareAmounts = new uint256[](2); shareAmounts[0] = 100; shareAmounts[1] = 100; - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); - queuedWithdrawalParams[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ strategies: strategyArray, depositShares: shareAmounts, withdrawer: defaultStaker }); - cheats.expectRevert(IDelegationManagerErrors.InputArrayLengthMismatch.selector); + cheats.expectRevert(InputArrayLengthMismatch.selector); delegationManager.queueWithdrawals(queuedWithdrawalParams); } function test_Revert_WhenNotStakerWithdrawer(address withdrawer) public { cheats.assume(withdrawer != defaultStaker); - (IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ + (QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, withdrawer: withdrawer, strategy: strategyMock, depositSharesToWithdraw: 100 }); - cheats.expectRevert(IDelegationManagerErrors.WithdrawerNotStaker.selector); + cheats.expectRevert(WithdrawerNotStaker.selector); cheats.prank(defaultStaker); delegationManager.queueWithdrawals(queuedWithdrawalParams); } @@ -3047,14 +3014,14 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes uint256[] memory shareAmounts = new uint256[](0); address withdrawer = defaultOperator; - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); - queuedWithdrawalParams[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ strategies: strategyArray, depositShares: shareAmounts, withdrawer: withdrawer }); - cheats.expectRevert(IDelegationManagerErrors.InputArrayLengthZero.selector); + cheats.expectRevert(InputArrayLengthZero.selector); delegationManager.queueWithdrawals(queuedWithdrawalParams); } @@ -3067,20 +3034,18 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes * - Checks that event was emitted with correct withdrawalRoot and withdrawal */ function testFuzz_queueWithdrawal_SingleStrat_nonSlashedOperator( - uint128 depositAmount, - uint128 withdrawalAmount - ) public { - cheats.assume(defaultStaker != defaultOperator); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); - uint256[] memory sharesAmounts = new uint256[](1); - sharesAmounts[0] = depositAmount; + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + uint256[] memory sharesAmounts = depositAmount.toArrayU256(); // sharesAmounts is single element so returns single strategy IStrategy[] memory strategies = _deployAndDepositIntoStrategies(defaultStaker, sharesAmounts); _registerOperatorWithBaseDetails(defaultOperator); _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -3114,13 +3079,10 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes * TODO: fuzz magnitude */ function testFuzz_queueWithdrawal_SingleStrat_preSlashedOperator( - uint128 depositAmount, - uint128 withdrawalAmount - ) public { - // TODO: remove these assumptions & properly handle rounding on division - cheats.assume(depositAmount % 2 == 0); - cheats.assume(withdrawalAmount % 2 == 0); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); // Slash the operator uint64 operatorMagnitude = 5e17; @@ -3128,18 +3090,16 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes _setOperatorMagnitude(defaultOperator, strategyMock, operatorMagnitude); // Deposit for staker & delegate - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = depositAmount; + uint256[] memory sharesToSet = depositAmount.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); } ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -3174,23 +3134,18 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes * TODO: fuzz magnitude */ function testFuzz_queueWithdrawal_SingleStrat_slashedWhileStaked( - uint128 depositAmount, - uint128 withdrawalAmount - ) public { - // TODO: remove these assumptions & properly handle rounding on division - cheats.assume(depositAmount % 2 == 0 && depositAmount > 1000); - cheats.assume(withdrawalAmount % 2 == 0); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); // Register operator _registerOperatorWithBaseDetails(defaultOperator); // Deposit for staker & delegate - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = depositAmount; + uint256[] memory sharesToSet = depositAmount.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); } @@ -3202,8 +3157,8 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes delegationManager.decreaseOperatorShares(defaultOperator, strategyMock, operatorMagnitude); ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -3212,9 +3167,7 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes depositSharesToWithdraw: withdrawalAmount }); - uint256[] memory sharesToWithdraw = new uint256[](1); - sharesToWithdraw[0] = withdrawalAmount / 2; - + uint256[] memory sharesToWithdraw = uint256(withdrawalAmount / 2).toArrayU256(); assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); uint256 delegatedSharesBefore = delegationManager.operatorShares(defaultOperator, strategies[0]); @@ -3262,11 +3215,9 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes _registerOperatorWithBaseDetails(defaultOperator); // Deposit for staker & delegate - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + IStrategy[] memory strategies = strategyMock.toArray(); { - uint256[] memory sharesToSet = new uint256[](1); - sharesToSet[0] = depositAmount; + uint256[] memory sharesToSet = depositAmount.toArrayU256(); strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); } @@ -3278,12 +3229,10 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes delegationManager.decreaseOperatorShares(defaultOperator, strategyMock, WAD); // Attempt to withdraw for the strategy that was slashed 100% for the operator - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); { - uint256[] memory withdrawalAmounts = new uint256[](1); - withdrawalAmounts[0] = withdrawalAmount; - - queuedWithdrawalParams[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + uint256[] memory withdrawalAmounts = withdrawalAmount.toArrayU256(); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ strategies: strategies, depositShares: withdrawalAmounts, withdrawer: defaultStaker @@ -3294,7 +3243,7 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes // queueWithdrawals should revert from the 100% slashing cheats.prank(defaultStaker); - cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(FullySlashed.selector); delegationManager.queueWithdrawals(queuedWithdrawalParams); (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); @@ -3330,8 +3279,8 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes _registerOperatorWithBaseDetails(defaultOperator); _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawals({ staker: defaultStaker, @@ -3367,14 +3316,14 @@ contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTes } contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManagerUnitTests { - // TODO: add upgrade tests for completing withdrawals queued before upgrade in integration tests + using SingleItemArrayLib for *; function test_Revert_WhenExitWithdrawalQueuePaused() public { cheats.prank(pauser); delegationManager.pause(2 ** PAUSED_EXIT_WITHDRAWAL_QUEUE); _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, /* bytes32 withdrawalRoot */ ) = _setUpCompleteQueuedWithdrawalSingleStrat({ @@ -3401,7 +3350,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage function test_Revert_WhenInputArrayLengthMismatch() public { _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, /* bytes32 withdrawalRoot */ ) = _setUpCompleteQueuedWithdrawalSingleStrat({ @@ -3416,7 +3365,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage tokens = new IERC20[](0); cheats.prank(defaultStaker); - cheats.expectRevert(IDelegationManagerErrors.InputArrayLengthMismatch.selector); + cheats.expectRevert(InputArrayLengthMismatch.selector); delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); IERC20[][] memory tokensArray = new IERC20[][](1); @@ -3426,7 +3375,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage receiveAsTokens[0] = false; cheats.prank(defaultStaker); - cheats.expectRevert(IDelegationManagerErrors.InputArrayLengthMismatch.selector); + cheats.expectRevert(InputArrayLengthMismatch.selector); delegationManager.completeQueuedWithdrawals(tokensArray, receiveAsTokens, 1); } @@ -3435,7 +3384,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, ) = _setUpCompleteQueuedWithdrawalSingleStrat({ staker: defaultStaker, @@ -3445,7 +3394,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage }); _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); - cheats.expectRevert(IDelegationManagerErrors.WithdrawerNotCaller.selector); + cheats.expectRevert(WithdrawerNotCaller.selector); cheats.prank(invalidCaller); delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); } @@ -3453,7 +3402,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage function test_Revert_WhenInvalidWithdrawalRoot() public { _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, bytes32 withdrawalRoot ) = _setUpCompleteQueuedWithdrawalSingleStrat({ @@ -3470,7 +3419,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); - cheats.expectRevert(IDelegationManagerErrors.WithdrawalNotQueued.selector); + cheats.expectRevert(WithdrawalNotQueued.selector); cheats.prank(defaultStaker); delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); } @@ -3489,7 +3438,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, /* bytes32 withdrawalRoot */ ) = _setUpCompleteQueuedWithdrawal({ @@ -3501,7 +3450,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage // prank as withdrawer address cheats.roll(withdrawal.startBlock + minWithdrawalDelayBlocks - 1); - cheats.expectRevert(IDelegationManagerErrors.WithdrawalDelayNotElapsed.selector); + cheats.expectRevert(WithdrawalDelayNotElapsed.selector); cheats.prank(defaultStaker); delegationManager.completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens); @@ -3511,7 +3460,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage bool[] memory receiveAsTokensArray = new bool[](1); receiveAsTokensArray[0] = false; - cheats.expectRevert(IDelegationManagerErrors.WithdrawalDelayNotElapsed.selector); + cheats.expectRevert(WithdrawalDelayNotElapsed.selector); cheats.prank(defaultStaker); delegationManager.completeQueuedWithdrawals(tokensArray, receiveAsTokensArray, 1); } @@ -3524,15 +3473,15 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot */ function test_completeQueuedWithdrawal_SingleStratWithdrawAsTokens( - address staker, - uint128 depositAmount, - uint128 withdrawalAmount - ) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != defaultOperator); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); + Randomness r + ) public rand(r) { + address staker = r.Address(); + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, bytes32 withdrawalRoot ) = _setUpCompleteQueuedWithdrawalSingleStrat({ @@ -3566,20 +3515,14 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage * - Asserts that the shares the staker completed withdrawal for are less than what is expected since its operator is slashed */ function test_completeQueuedWithdrawal_SingleStratWithdrawAsTokens_slashOperatorDuringQueue( - uint128 depositAmount, - uint128 withdrawalAmount - ) public { - // TODO: remove these assumptions & properly handle rounding on division - cheats.assume(depositAmount % 2 == 0); - cheats.assume(withdrawalAmount % 2 == 0); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); - + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); // Deposit Staker - uint256[] memory depositAmounts = new uint256[](1); - depositAmounts[0] = depositAmount; - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategyMock; + uint256[] memory depositAmounts = depositAmount.toArrayU256(); + IStrategy[] memory strategies = strategyMock.toArray(); strategyManagerMock.setDeposits(defaultStaker, strategies, depositAmounts); // Register operator and delegate to it @@ -3589,8 +3532,8 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage // Queue withdrawal ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -3611,7 +3554,7 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage cheats.prank(address(allocationManagerMock)); delegationManager.decreaseOperatorShares(defaultOperator, withdrawal.strategies[0], operatorMagnitude); uint256 operatorSharesAfterSlash = delegationManager.operatorShares(defaultOperator, strategyMock); - assertEq(operatorSharesAfterSlash, operatorSharesAfterQueue / 2, "operator shares should be decreased after slash"); + assertApproxEqAbs(operatorSharesAfterSlash, operatorSharesAfterQueue / 2, 1, "operator shares should be decreased after slash"); // Complete queue withdrawal IERC20[] memory tokens = new IERC20[](1); @@ -3642,13 +3585,10 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage */ // TODO: fuzz the beacon chain magnitude function test_completeQueuedWithdrawal_BeaconStratWithdrawAsTokens_slashStakerDuringQueue( - uint128 depositAmount, - uint128 withdrawalAmount - ) public { - // TODO: remove these assumptions & properly handle rounding on division - cheats.assume(depositAmount % 2 == 0); - cheats.assume(withdrawalAmount % 2 == 0); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); // Deposit Staker eigenPodManagerMock.setPodOwnerShares(defaultStaker, int256(uint256(depositAmount))); @@ -3660,8 +3600,8 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage // Queue withdrawal ( - IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManagerTypes.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, @@ -3710,79 +3650,75 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage * - Asserts that the shares the staker completed withdrawal for are less than what is expected since both the staker and its operator are slashed during queue */ // TODO: fuzz the beacon chain magnitude & operator magnitude - // TODO: fix rounding error - // function test_completeQueuedWithdrawal_BeaconStratWithdrawAsTokens_slashStakerAndOperator( - // uint128 depositAmount, - // uint128 withdrawalAmount - // ) public { - // // TODO: remove these assumptions & properly handle rounding on division - // cheats.assume(depositAmount % 2 == 0); - // cheats.assume(withdrawalAmount % 2 == 0); - // cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); - - // // Deposit Staker - // eigenPodManagerMock.setPodOwnerShares(defaultStaker, int256(uint256(depositAmount))); - - // // Register operator and delegate to it - // _registerOperatorWithBaseDetails(defaultOperator); - // _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); - // uint256 operatorSharesBeforeQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - - // // Queue withdrawal - // ( - // IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - // IDelegationManagerTypes.Withdrawal memory withdrawal, - // bytes32 withdrawalRoot - // ) = _setUpQueueWithdrawalsSingleStrat({ - // staker: defaultStaker, - // withdrawer: defaultStaker, - // strategy: beaconChainETHStrategy, - // depositSharesToWithdraw: withdrawalAmount - // }); - - // { - // cheats.prank(defaultStaker); - // delegationManager.queueWithdrawals(queuedWithdrawalParams); - // assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); - // uint256 operatorSharesAfterQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - // assertEq(operatorSharesAfterQueue, operatorSharesBeforeQueue - withdrawalAmount, "operator shares should be decreased after queue"); - - // // Slash the staker for beacon chain shares while it has queued a withdrawal - // uint256 beaconSharesBeforeSlash = uint256(eigenPodManagerMock.podOwnerShares(defaultStaker)); - // uint64 stakerBeaconChainScalingFactor = 5e17; - // cheats.prank(address(eigenPodManagerMock)); - // delegationManager.decreaseBeaconChainScalingFactor(defaultStaker, beaconSharesBeforeSlash, stakerBeaconChainScalingFactor); - // uint256 operatorSharesAfterBeaconSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - // assertEq(operatorSharesAfterBeaconSlash, operatorSharesAfterQueue / 2, "operator shares should be decreased after beaconChain slash"); - - // // Slash the operator for beacon chain shares - // uint64 operatorMagnitude = 5e17; - // _setOperatorMagnitude(defaultOperator, withdrawal.strategies[0], operatorMagnitude); - // cheats.prank(address(allocationManagerMock)); - // delegationManager.decreaseOperatorShares(defaultOperator, withdrawal.strategies[0], operatorMagnitude); - // uint256 operatorSharesAfterAVSSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - // assertEq(operatorSharesAfterAVSSlash, operatorSharesAfterBeaconSlash / 2, "operator shares should be decreased after AVS slash"); - // } - // uint256 operatorSharesAfterAVSSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - - - // // Complete queue withdrawal - // IERC20[] memory tokens = new IERC20[](1); - // cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); - // cheats.prank(defaultStaker); - // cheats.expectEmit(true, true, true, true, address(delegationManager)); - // emit SlashingWithdrawalCompleted(withdrawalRoot); - // delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); - - // // Checks: operator shares - // uint256 operatorSharesAfterWithdrawalComplete = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); - // assertEq(operatorSharesAfterWithdrawalComplete, operatorSharesAfterAVSSlash, "operator shares should be unchanged from slash to withdrawal completion"); - // assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); - - // // Checks: staker shares - // uint256 stakerBeaconSharesWithdrawn = eigenPodManagerMock.podOwnerSharesWithdrawn(defaultStaker); - // assertEq(stakerBeaconSharesWithdrawn, withdrawalAmount / 4, "staker shares withdrawn should be 1/4th of expected it is slashed by half twice"); - // } + function test_completeQueuedWithdrawal_BeaconStratWithdrawAsTokens_slashStakerAndOperator( + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + + // Deposit Staker + eigenPodManagerMock.setPodOwnerShares(defaultStaker, int256(uint256(depositAmount))); + + // Register operator and delegate to it + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + uint256 operatorSharesBeforeQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + + // Queue withdrawal + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: beaconChainETHStrategy, + depositSharesToWithdraw: withdrawalAmount + }); + + uint256 operatorSharesAfterAVSSlash; + { + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + uint256 operatorSharesAfterQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesAfterQueue, operatorSharesBeforeQueue - withdrawalAmount, "operator shares should be decreased after queue"); + + // Slash the staker for beacon chain shares while it has queued a withdrawal + uint256 beaconSharesBeforeSlash = uint256(eigenPodManagerMock.podOwnerShares(defaultStaker)); + uint64 stakerBeaconChainScalingFactor = 5e17; + cheats.prank(address(eigenPodManagerMock)); + delegationManager.decreaseBeaconChainScalingFactor(defaultStaker, beaconSharesBeforeSlash, stakerBeaconChainScalingFactor); + uint256 operatorSharesAfterBeaconSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesAfterBeaconSlash, operatorSharesAfterQueue / 2, "operator shares should be decreased after beaconChain slash"); + + // Slash the operator for beacon chain shares + uint64 operatorMagnitude = 5e17; + _setOperatorMagnitude(defaultOperator, withdrawal.strategies[0], operatorMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.decreaseOperatorShares(defaultOperator, withdrawal.strategies[0], operatorMagnitude); + operatorSharesAfterAVSSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertApproxEqAbs(operatorSharesAfterAVSSlash, operatorSharesAfterBeaconSlash / 2, 1, "operator shares should be decreased after AVS slash"); + } + operatorSharesAfterAVSSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + + // Complete queue withdrawal + IERC20[] memory tokens = new IERC20[](1); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(defaultStaker); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoot); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + + // Checks: operator shares + uint256 operatorSharesAfterWithdrawalComplete = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + assertEq(operatorSharesAfterWithdrawalComplete, operatorSharesAfterAVSSlash, "operator shares should be unchanged from slash to withdrawal completion"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + + // Checks: staker shares + uint256 stakerBeaconSharesWithdrawn = eigenPodManagerMock.podOwnerSharesWithdrawn(defaultStaker); + assertEq(stakerBeaconSharesWithdrawn, withdrawalAmount / 4, "staker shares withdrawn should be 1/4th of expected it is slashed by half twice"); + } /** @@ -3793,18 +3729,17 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage * - Asserts if staker == withdrawer, operatorShares increase, otherwise operatorShares are unchanged * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot */ - function test_completeQueuedWithdrawal_SingleStratWithdrawAsShares_nonSlashedOperator( - address staker, - uint128 depositAmount, - uint128 withdrawalAmount - ) public filterFuzzedAddressInputs(staker) { - // TODO: remove these assumptions & properly handle rounding on division - cheats.assume(staker != defaultOperator); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); + function testFuzz_completeQueuedWithdrawal_SingleStratWithdrawAsShares_nonSlashedOperator( + Randomness r + ) public rand(r) { + address staker = r.Address(); + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + _registerOperatorWithBaseDetails(defaultOperator); ( - IDelegationManagerTypes.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, IERC20[] memory tokens, bytes32 withdrawalRoot ) = _setUpCompleteQueuedWithdrawalSingleStrat({ @@ -3832,11 +3767,8 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage assertEq(operatorSharesAfter, operatorSharesBefore + withdrawalAmount, "operator shares not increased correctly"); assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); } - - // TODO: add slashing cases for withdrawing as shares (can also be in integration tests) } - /** * @notice TODO Lifecycle tests - These tests combine multiple functionalities of the DelegationManager 1. Old SigP test - registerAsOperator, separate staker delegate to operator, as operator undelegate (reverts), @@ -3850,3 +3782,58 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage 8. RegisterOperator, Deposit/Delegate, Undelegate, Re delegate to another operator, Mock Slash 100% (set maxMagnitudes), Complete as shares (withdrawals should have been slashed even though delegated to a new operator) */ + +contract DelegationManagerUnitTests_Lifecycle is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + + // 2. RegisterOperator, Deposit, Delegate, Queue, Complete + function test_register_operator_deposit_delegate_queue_complete(Randomness r) public rand(r) { + address operator = r.Address(); + address staker = r.Address(); + IStrategy[] memory strategies = strategyMock.toArray(); + uint256[] memory depositShares = uint256(100 ether).toArrayU256(); + + // 1) Register operator. + _registerOperatorWithBaseDetails(operator); + + // 2) Mock deposit into SM. + strategyManagerMock.setDeposits(staker, strategies, depositShares); + + // 3) Staker delegates to operator. + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + + // 3) Staker queues withdrawals. + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ + strategies: strategies, + depositShares: depositShares, + withdrawer: staker + }); + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + // 4) Complete queued withdrawals. + Withdrawal memory withdrawal = Withdrawal({ + staker: staker, + delegatedTo: operator, + withdrawer: staker, + nonce: 0, + startBlock: uint32(block.number), + strategies: strategies, + scaledShares: depositShares + }); + + bytes32 withdrawalRoot = keccak256(abi.encode(withdrawal)); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + cheats.roll(block.number + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + + cheats.prank(staker); + delegationManager.completeQueuedWithdrawal(withdrawal, tokenMock.toArray(), false); + + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should not be pending"); + + // Checks + assertEq(delegationManager.cumulativeWithdrawalsQueued(staker), 1, "staker nonce should have incremented"); + assertEq(delegationManager.operatorShares(operator, strategies[0]), 100 ether, "operator shares should be 0 after withdrawal"); + } +} \ No newline at end of file diff --git a/src/test/utils/Random.sol b/src/test/utils/Random.sol index 4b6ae3cfc..e239f388b 100644 --- a/src/test/utils/Random.sol +++ b/src/test/utils/Random.sol @@ -102,6 +102,12 @@ library Random { return address(uint160(r.Uint256(1, type(uint160).max))); } + function Boolean( + Randomness r + ) internal returns (bool) { + return r.Uint256() % 2 == 0; + } + /// ----------------------------------------------------------------------- /// General Types /// ----------------------------------------------------------------------- diff --git a/src/test/utils/SingleItemArrayLib.sol b/src/test/utils/SingleItemArrayLib.sol index b864e5b9e..8fbadbacd 100644 --- a/src/test/utils/SingleItemArrayLib.sol +++ b/src/test/utils/SingleItemArrayLib.sol @@ -78,6 +78,17 @@ library SingleItemArrayLib { } } + /// ----------------------------------------------------------------------- + /// EigenLayer Types + /// ----------------------------------------------------------------------- + + function toArray( + IERC20 token + ) internal pure returns (IERC20[] memory array) { + array = new IERC20[](1); + array[0] = token; + } + function toArray( IStrategy strategy ) internal pure returns (IStrategy[] memory array) { @@ -85,10 +96,6 @@ library SingleItemArrayLib { array[0] = strategy; } - /// ----------------------------------------------------------------------- - /// EigenLayer Types - /// ----------------------------------------------------------------------- - function toArray( OperatorSet memory operatorSet ) internal pure returns (OperatorSet[] memory array) {