Skip to content

Commit 36b69da

Browse files
committed
refactor: small cleanup
refactor small cleanup chore: `forge fmt` fix: `getQueuedWithdrawals` + test fix: add constructor back test: `totalQueued` > `withdrawal.strategies.length` test(wip): `completeQueuedWithdrawals` currently failing fix: effectBlock
1 parent 2535685 commit 36b69da

File tree

7 files changed

+314
-4
lines changed

7 files changed

+314
-4
lines changed

src/contracts/core/AllocationManager.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ contract AllocationManager is
6363
// Check that the operator set exists and the operator is registered to it
6464
OperatorSet memory operatorSet = OperatorSet(avs, params.operatorSetId);
6565
bool isOperatorSlashable = _isOperatorSlashable(params.operator, operatorSet);
66+
require(params.strategies.length == params.wadsToSlash.length, InputArrayLengthMismatch());
6667
require(_operatorSets[operatorSet.avs].contains(operatorSet.id), InvalidOperatorSet());
6768
require(isOperatorSlashable, OperatorNotSlashable());
6869

src/contracts/core/DelegationManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ contract DelegationManager is
942942
for (uint256 j; j < withdrawals[i].strategies.length; ++j) {
943943
shares[i][j] = SlashingLib.scaleForCompleteWithdrawal({
944944
scaledShares: withdrawals[i].scaledShares[j],
945-
slashingFactor: slashingFactors[i]
945+
slashingFactor: slashingFactors[j]
946946
});
947947
}
948948
}

src/contracts/interfaces/IAllocationManager.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pragma solidity >=0.5.0;
44
import {OperatorSet} from "../libraries/OperatorSetLib.sol";
55
import "./IPauserRegistry.sol";
66
import "./IStrategy.sol";
7-
import "./ISignatureUtils.sol";
87
import "./IAVSRegistrar.sol";
98

109
interface IAllocationManagerErrors {
@@ -213,7 +212,7 @@ interface IAllocationManagerEvents is IAllocationManagerTypes {
213212
event StrategyRemovedFromOperatorSet(OperatorSet operatorSet, IStrategy strategy);
214213
}
215214

216-
interface IAllocationManager is ISignatureUtils, IAllocationManagerErrors, IAllocationManagerEvents {
215+
interface IAllocationManager is IAllocationManagerErrors, IAllocationManagerEvents {
217216
/**
218217
* @dev Initializes the initial owner and paused status.
219218
*/

src/test/unit/AllocationManagerUnit.t.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,15 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests
613613
allocationManager.slashOperator(defaultAVS, _randSlashingParams(random().Address(), 0));
614614
}
615615

616+
function test_revert_InputArrayLengthMismatch() public {
617+
SlashingParams memory slashingParams = _randSlashingParams(defaultOperator, 0);
618+
slashingParams.strategies = slashingParams.strategies.setLength(2);
619+
620+
cheats.prank(defaultAVS);
621+
cheats.expectRevert(InputArrayLengthMismatch.selector);
622+
allocationManager.slashOperator(defaultAVS, slashingParams);
623+
}
624+
616625
function test_revert_StrategiesMustBeInAscendingOrder() public {
617626
IStrategy[] memory strategies = new IStrategy[](3);
618627
strategies[0] = IStrategy(address(3));

src/test/unit/DelegationUnit.t.sol

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag
6868
// Helper to use in storage
6969
DepositScalingFactor dsf;
7070
uint256 stakerDSF;
71-
uint256 slashingFactor;
7271

7372
/// @notice mappings used to handle duplicate entries in fuzzed address array input
7473
mapping(address => uint256) public totalSharesForStrategyInArray;
@@ -6514,6 +6513,69 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage
65146513
assertEq(operatorSharesAfter, operatorSharesBefore + withdrawalAmount, "operator shares not increased correctly");
65156514
assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now");
65166515
}
6516+
6517+
function testFuzz_completeQueuedWithdrawals_OutOfOrderBlocking(Randomness r) public {
6518+
uint256 totalDepositShares = r.Uint256(4, 100 ether);
6519+
uint256 depositSharesPerWithdrawal = totalDepositShares / 4;
6520+
6521+
_registerOperatorWithBaseDetails(defaultOperator);
6522+
strategyManagerMock.addDeposit(defaultStaker, strategyMock, totalDepositShares);
6523+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
6524+
6525+
QueuedWithdrawalParams[] memory queuedParams = new QueuedWithdrawalParams[](4);
6526+
Withdrawal[] memory withdrawals = new Withdrawal[](4);
6527+
6528+
uint256 startBlock = block.number;
6529+
6530+
for (uint256 i; i < 4; ++i) {
6531+
cheats.roll(startBlock + i);
6532+
(
6533+
QueuedWithdrawalParams[] memory params,
6534+
Withdrawal memory withdrawal,
6535+
) = _setUpQueueWithdrawalsSingleStrat(
6536+
defaultStaker,
6537+
defaultStaker,
6538+
strategyMock,
6539+
depositSharesPerWithdrawal
6540+
);
6541+
6542+
(queuedParams[i], withdrawals[i]) = (params[0], withdrawal);
6543+
}
6544+
6545+
uint256 delay = delegationManager.minWithdrawalDelayBlocks();
6546+
6547+
cheats.startPrank(defaultStaker);
6548+
cheats.roll(startBlock);
6549+
6550+
// assertEq(queuedParams[0].effectBlock, block.timestamp);
6551+
delegationManager.queueWithdrawals(queuedParams[0].toArray());
6552+
cheats.roll(startBlock + 1);
6553+
delegationManager.queueWithdrawals(queuedParams[1].toArray());
6554+
6555+
(
6556+
Withdrawal[] memory firstWithdrawals,
6557+
uint256[][] memory firstShares
6558+
) = delegationManager.getQueuedWithdrawals(defaultStaker);
6559+
6560+
cheats.roll(startBlock + 2);
6561+
delegationManager.queueWithdrawals(queuedParams[2].toArray());
6562+
cheats.roll(startBlock + 3);
6563+
delegationManager.queueWithdrawals(queuedParams[3].toArray());
6564+
6565+
IERC20[][] memory tokens = new IERC20[][](2);
6566+
bool[] memory receiveAsTokens = new bool[](2);
6567+
for (uint256 i; i < 2; ++i) {
6568+
tokens[i] = strategyMock.underlyingToken().toArray();
6569+
}
6570+
6571+
cheats.roll(startBlock + delay + 1);
6572+
delegationManager.completeQueuedWithdrawals(firstWithdrawals, tokens, true.toArray(2));
6573+
6574+
// Throws `WithdrawalNotQueued`.
6575+
cheats.roll(startBlock + delay + 2);
6576+
delegationManager.completeQueuedWithdrawals(withdrawals[2].toArray(), tokens, true.toArray());
6577+
cheats.stopPrank();
6578+
}
65176579
}
65186580

65196581
contract DelegationManagerUnitTests_burningShares is DelegationManagerUnitTests {
@@ -8192,3 +8254,121 @@ contract DelegationManagerUnitTests_Lifecycle is DelegationManagerUnitTests {
81928254
assertEq(delegationManager.operatorShares(newOperator, strategy), 0, "new operator shares should be unchanged");
81938255
}
81948256
}
8257+
8258+
contract DelegationManagerUnitTests_getQueuedWithdrawals is DelegationManagerUnitTests {
8259+
using ArrayLib for *;
8260+
using SlashingLib for *;
8261+
8262+
function _withdrawalRoot(Withdrawal memory withdrawal) internal pure returns (bytes32) {
8263+
return keccak256(abi.encode(withdrawal));
8264+
}
8265+
8266+
function test_getQueuedWithdrawals_Correctness(Randomness r) public {
8267+
uint256 numStrategies = r.Uint256(2, 8);
8268+
uint256[] memory depositShares = r.Uint256Array({
8269+
len: numStrategies,
8270+
min: 2,
8271+
max: 100 ether
8272+
});
8273+
8274+
IStrategy[] memory strategies = _deployAndDepositIntoStrategies(defaultStaker, depositShares, false);
8275+
_registerOperatorWithBaseDetails(defaultOperator);
8276+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
8277+
8278+
for (uint256 i; i < numStrategies; ++i) {
8279+
uint256 newStakerShares = depositShares[i] / 2;
8280+
_setOperatorMagnitude(defaultOperator, strategies[i], 0.5 ether);
8281+
cheats.prank(address(allocationManagerMock));
8282+
delegationManager.burnOperatorShares(defaultOperator, strategies[i], WAD, 0.5 ether);
8283+
uint256 afterSlash = delegationManager.operatorShares(defaultOperator, strategies[i]);
8284+
assertApproxEqAbs(afterSlash, newStakerShares, 1, "bad operator shares after slash");
8285+
}
8286+
8287+
// Queue withdrawals.
8288+
(
8289+
QueuedWithdrawalParams[] memory queuedWithdrawalParams,
8290+
Withdrawal memory withdrawal,
8291+
bytes32 withdrawalRoot
8292+
) = _setUpQueueWithdrawals({
8293+
staker: defaultStaker,
8294+
withdrawer: defaultStaker,
8295+
strategies: strategies,
8296+
depositWithdrawalAmounts: depositShares
8297+
});
8298+
8299+
cheats.prank(defaultStaker);
8300+
delegationManager.queueWithdrawals(queuedWithdrawalParams);
8301+
8302+
// Get queued withdrawals.
8303+
(Withdrawal[] memory withdrawals, uint256[][] memory shares) = delegationManager.getQueuedWithdrawals(defaultStaker);
8304+
8305+
// Checks
8306+
for (uint256 i; i < numStrategies; ++i) {
8307+
uint256 newStakerShares = depositShares[i] / 2;
8308+
assertApproxEqAbs(shares[0][i], newStakerShares, 1, "staker shares should be decreased by half +- 1");
8309+
}
8310+
8311+
assertEq(_withdrawalRoot(withdrawal), _withdrawalRoot(withdrawals[0]), "_withdrawalRoot(withdrawal) != _withdrawalRoot(withdrawals[0])");
8312+
assertEq(_withdrawalRoot(withdrawal), withdrawalRoot, "_withdrawalRoot(withdrawal) != withdrawalRoot");
8313+
}
8314+
8315+
function test_getQueuedWithdrawals_TotalQueuedGreaterThanTotalStrategies(Randomness r) public {
8316+
uint256 totalDepositShares = r.Uint256(2, 100 ether);
8317+
8318+
_registerOperatorWithBaseDetails(defaultOperator);
8319+
strategyManagerMock.addDeposit(defaultStaker, strategyMock, totalDepositShares);
8320+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
8321+
8322+
uint256 newStakerShares = totalDepositShares / 2;
8323+
_setOperatorMagnitude(defaultOperator, strategyMock, 0.5 ether);
8324+
cheats.prank(address(allocationManagerMock));
8325+
delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, 0.5 ether);
8326+
uint256 afterSlash = delegationManager.operatorShares(defaultOperator, strategyMock);
8327+
assertApproxEqAbs(afterSlash, newStakerShares, 1, "bad operator shares after slash");
8328+
8329+
// Queue withdrawals.
8330+
(
8331+
QueuedWithdrawalParams[] memory queuedWithdrawalParams0,
8332+
Withdrawal memory withdrawal0,
8333+
bytes32 withdrawalRoot0
8334+
) = _setUpQueueWithdrawalsSingleStrat({
8335+
staker: defaultStaker,
8336+
withdrawer: defaultStaker,
8337+
strategy: strategyMock,
8338+
depositSharesToWithdraw: totalDepositShares / 2
8339+
});
8340+
8341+
cheats.prank(defaultStaker);
8342+
delegationManager.queueWithdrawals(queuedWithdrawalParams0);
8343+
8344+
(
8345+
QueuedWithdrawalParams[] memory queuedWithdrawalParams1,
8346+
Withdrawal memory withdrawal1,
8347+
bytes32 withdrawalRoot1
8348+
) = _setUpQueueWithdrawalsSingleStrat({
8349+
staker: defaultStaker,
8350+
withdrawer: defaultStaker,
8351+
strategy: strategyMock,
8352+
depositSharesToWithdraw: totalDepositShares / 2
8353+
});
8354+
8355+
cheats.prank(defaultStaker);
8356+
delegationManager.queueWithdrawals(queuedWithdrawalParams1);
8357+
8358+
// Get queued withdrawals.
8359+
(Withdrawal[] memory withdrawals, uint256[][] memory shares) = delegationManager.getQueuedWithdrawals(defaultStaker);
8360+
8361+
// Sanity
8362+
assertEq(withdrawals.length, 2, "withdrawal.length != 2");
8363+
assertEq(withdrawals[0].strategies.length, 1, "withdrawals[0].strategies.length != 1");
8364+
assertEq(withdrawals[1].strategies.length, 1, "withdrawals[1].strategies.length != 1");
8365+
8366+
// Checks
8367+
assertApproxEqAbs(shares[0][0], newStakerShares / 2, 1, "shares[0][0] != newStakerShares");
8368+
assertApproxEqAbs(shares[1][0], newStakerShares / 2, 1, "shares[1][0] != newStakerShares");
8369+
assertEq(_withdrawalRoot(withdrawal0), _withdrawalRoot(withdrawals[0]), "withdrawal0 != withdrawals[0]");
8370+
assertEq(_withdrawalRoot(withdrawal1), _withdrawalRoot(withdrawals[1]), "withdrawal1 != withdrawals[1]");
8371+
assertEq(_withdrawalRoot(withdrawal0), withdrawalRoot0, "_withdrawalRoot(withdrawal0) != withdrawalRoot0");
8372+
assertEq(_withdrawalRoot(withdrawal1), withdrawalRoot1, "_withdrawalRoot(withdrawal1) != withdrawalRoot1");
8373+
}
8374+
}

src/test/utils/ArrayLib.sol

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ library ArrayLib {
152152
array[0] = withdrawal;
153153
}
154154

155+
function toArray(
156+
IDelegationManagerTypes.QueuedWithdrawalParams memory queuedWithdrawalParams
157+
) internal pure returns (IDelegationManagerTypes.QueuedWithdrawalParams[] memory array) {
158+
array = new IDelegationManagerTypes.QueuedWithdrawalParams[](1);
159+
array[0] = queuedWithdrawalParams;
160+
}
161+
155162
/// -----------------------------------------------------------------------
156163
/// Length Updates
157164
/// -----------------------------------------------------------------------
@@ -236,6 +243,16 @@ library ArrayLib {
236243
return array;
237244
}
238245

246+
function setLength(
247+
IDelegationManagerTypes.Withdrawal[] memory array,
248+
uint256 len
249+
) internal pure returns (IDelegationManagerTypes.Withdrawal[] memory) {
250+
assembly {
251+
mstore(array, len)
252+
}
253+
return array;
254+
}
255+
239256
/// -----------------------------------------------------------------------
240257
/// Contains
241258
/// -----------------------------------------------------------------------
@@ -310,6 +327,26 @@ library ArrayLib {
310327
return false;
311328
}
312329

330+
function contains(
331+
OperatorSet[] memory array,
332+
OperatorSet memory x
333+
) internal pure returns (bool) {
334+
for (uint256 i; i < array.length; ++i) {
335+
if (keccak256(abi.encode(array[i])) == keccak256(abi.encode(x))) return true;
336+
}
337+
return false;
338+
}
339+
340+
function contains(
341+
IDelegationManagerTypes.Withdrawal[] memory array,
342+
IDelegationManagerTypes.Withdrawal memory x
343+
) internal pure returns (bool) {
344+
for (uint256 i; i < array.length; ++i) {
345+
if (keccak256(abi.encode(array[i])) == keccak256(abi.encode(x))) return true;
346+
}
347+
return false;
348+
}
349+
313350
/// -----------------------------------------------------------------------
314351
/// indexOf
315352
/// -----------------------------------------------------------------------
@@ -384,6 +421,26 @@ library ArrayLib {
384421
return type(uint256).max;
385422
}
386423

424+
function indexOf(
425+
OperatorSet[] memory array,
426+
OperatorSet memory x
427+
) internal pure returns (uint256) {
428+
for (uint256 i; i < array.length; ++i) {
429+
if (keccak256(abi.encode(array[i])) == keccak256(abi.encode(x))) return i;
430+
}
431+
return type(uint256).max;
432+
}
433+
434+
function indexOf(
435+
IDelegationManagerTypes.Withdrawal[] memory array,
436+
IDelegationManagerTypes.Withdrawal memory x
437+
) internal pure returns (uint256) {
438+
for (uint256 i; i < array.length; ++i) {
439+
if (keccak256(abi.encode(array[i])) == keccak256(abi.encode(x))) return i;
440+
}
441+
return type(uint256).max;
442+
}
443+
387444
/// -----------------------------------------------------------------------
388445
/// Sorting
389446
/// -----------------------------------------------------------------------

0 commit comments

Comments
 (0)