Skip to content

Commit 8d380fa

Browse files
committed
test: burning indices
1 parent 6ffb6c3 commit 8d380fa

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed

src/test/unit/DelegationUnit.t.sol

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6000,6 +6000,48 @@ contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManage
60006000
delegationManager.completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens);
60016001
}
60026002

6003+
/// @notice Verifies that when we complete a withdrawal as shares after a full slash, we revert
6004+
function test_revert_fullySlashed() public {
6005+
// Register operator
6006+
_registerOperatorWithBaseDetails(defaultOperator);
6007+
_setOperatorMagnitude(defaultOperator, strategyMock, WAD);
6008+
6009+
// Set the staker deposits in the strategies
6010+
uint256 depositAmount = 100e18;
6011+
strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount);
6012+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
6013+
6014+
// Queue withdrawal
6015+
uint256 withdrawalAmount = depositAmount;
6016+
(
6017+
QueuedWithdrawalParams[] memory queuedWithdrawalParams,
6018+
Withdrawal memory withdrawal,
6019+
bytes32 withdrawalRoot
6020+
) = _setUpQueueWithdrawalsSingleStrat({
6021+
staker: defaultStaker,
6022+
withdrawer: defaultStaker,
6023+
strategy: strategyMock,
6024+
depositSharesToWithdraw: withdrawalAmount
6025+
});
6026+
cheats.prank(defaultStaker);
6027+
delegationManager.queueWithdrawals(queuedWithdrawalParams);
6028+
6029+
// Warp to just before the MIN_WITHDRAWAL_DELAY_BLOCKS
6030+
cheats.roll(withdrawal.startBlock + delegationManager.minWithdrawalDelayBlocks());
6031+
6032+
// Slash all of operator's shares
6033+
_setOperatorMagnitude(defaultOperator, strategyMock, 0);
6034+
cheats.prank(address(allocationManagerMock));
6035+
delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, 0);
6036+
6037+
// Complete withdrawal as shares and assert that operator has no shares increased
6038+
cheats.roll(block.number + 1);
6039+
IERC20[] memory tokens = strategyMock.underlyingToken().toArray();
6040+
cheats.expectRevert(FullySlashed.selector);
6041+
cheats.prank(defaultStaker);
6042+
delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false);
6043+
}
6044+
60036045
/**
60046046
* Test completing multiple queued withdrawals for a single strategy by passing in the withdrawals
60056047
*/
@@ -6539,6 +6581,172 @@ contract DelegationManagerUnitTests_burningShares is DelegationManagerUnitTests
65396581
assertEq(delegationManager.operatorShares(defaultOperator, strategyMock), 0, "shares should not have changed");
65406582
}
65416583

6584+
/// @notice Verifies that shares are burnable for a withdrawal slashed just before the MIN_WITHDRAWAL_DELAY_BLOCKS is hit
6585+
function test_sharesBurnableAtMinDelayBlocks() public {
6586+
// Register operator
6587+
_registerOperatorWithBaseDetails(defaultOperator);
6588+
_setOperatorMagnitude(defaultOperator, strategyMock, WAD);
6589+
6590+
// Set the staker deposits in the strategies
6591+
uint256 depositAmount = 100e18;
6592+
strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount);
6593+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
6594+
6595+
// Queue withdrawal
6596+
uint256 withdrawalAmount = depositAmount;
6597+
(
6598+
QueuedWithdrawalParams[] memory queuedWithdrawalParams,
6599+
Withdrawal memory withdrawal,
6600+
bytes32 withdrawalRoot
6601+
) = _setUpQueueWithdrawalsSingleStrat({
6602+
staker: defaultStaker,
6603+
withdrawer: defaultStaker,
6604+
strategy: strategyMock,
6605+
depositSharesToWithdraw: withdrawalAmount
6606+
});
6607+
cheats.prank(defaultStaker);
6608+
delegationManager.queueWithdrawals(queuedWithdrawalParams);
6609+
6610+
// Warp to just before the MIN_WITHDRAWAL_DELAY_BLOCKS
6611+
cheats.roll(withdrawal.startBlock + delegationManager.minWithdrawalDelayBlocks());
6612+
6613+
// Slash all of operator's shares
6614+
_setOperatorMagnitude(defaultOperator, strategyMock, 0);
6615+
cheats.prank(address(allocationManagerMock));
6616+
delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, 0);
6617+
6618+
// Complete withdrawal as tokens and assert that nothing is returned
6619+
cheats.roll(block.number + 1);
6620+
IERC20[] memory tokens = strategyMock.underlyingToken().toArray();
6621+
cheats.expectCall(
6622+
address(strategyManagerMock),
6623+
abi.encodeWithSelector(
6624+
IShareManager.withdrawSharesAsTokens.selector,
6625+
defaultStaker,
6626+
strategyMock,
6627+
strategyMock.underlyingToken(),
6628+
0
6629+
)
6630+
);
6631+
cheats.prank(defaultStaker);
6632+
delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true);
6633+
}
6634+
6635+
/// @notice Verifies that shares are NOT burnable for a withdrawal queued just before the MIN_WITHDRAWAL_DELAY_BLOCKS
6636+
function test_sharesNotBurnableWhenWithdrawalCompletable() public {
6637+
// Register operator
6638+
_registerOperatorWithBaseDetails(defaultOperator);
6639+
_setOperatorMagnitude(defaultOperator, strategyMock, WAD);
6640+
6641+
// Set the staker deposits in the strategies
6642+
uint256 depositAmount = 100e18;
6643+
strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount);
6644+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
6645+
6646+
// Queue withdrawal
6647+
uint256 withdrawalAmount = depositAmount;
6648+
(
6649+
QueuedWithdrawalParams[] memory queuedWithdrawalParams,
6650+
Withdrawal memory withdrawal,
6651+
bytes32 withdrawalRoot
6652+
) = _setUpQueueWithdrawalsSingleStrat({
6653+
staker: defaultStaker,
6654+
withdrawer: defaultStaker,
6655+
strategy: strategyMock,
6656+
depositSharesToWithdraw: withdrawalAmount
6657+
});
6658+
cheats.prank(defaultStaker);
6659+
delegationManager.queueWithdrawals(queuedWithdrawalParams);
6660+
6661+
// Warp to completion time
6662+
cheats.roll(withdrawal.startBlock + delegationManager.minWithdrawalDelayBlocks() + 1);
6663+
uint256 slashableShares = delegationManager.getSlashableSharesInQueue(defaultOperator, strategyMock);
6664+
assertEq(slashableShares, 0, "shares should not be slashable");
6665+
6666+
// Slash all of operator's shares
6667+
_setOperatorMagnitude(defaultOperator, strategyMock, 0);
6668+
cheats.prank(address(allocationManagerMock));
6669+
delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, 0);
6670+
6671+
// Complete withdrawal as tokens and assert that we call back into teh SM with 100 tokens
6672+
IERC20[] memory tokens = strategyMock.underlyingToken().toArray();
6673+
cheats.expectCall(
6674+
address(strategyManagerMock),
6675+
abi.encodeWithSelector(
6676+
IShareManager.withdrawSharesAsTokens.selector,
6677+
defaultStaker,
6678+
strategyMock,
6679+
strategyMock.underlyingToken(),
6680+
100e18
6681+
)
6682+
);
6683+
cheats.prank(defaultStaker);
6684+
delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true);
6685+
}
6686+
6687+
/**
6688+
* @notice Queues 5 withdrawals at different blocks. Then, warps such that the first 2 are completable. Validates the slashable shares
6689+
*/
6690+
function test_slashableSharesInQueue() public {
6691+
// Register operator
6692+
_registerOperatorWithBaseDetails(defaultOperator);
6693+
_setOperatorMagnitude(defaultOperator, strategyMock, WAD);
6694+
6695+
// Set the staker deposits in the strategies
6696+
uint256 depositAmount = 120e18;
6697+
strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount);
6698+
_delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator);
6699+
6700+
// Queue 5 withdrawals
6701+
uint256 startBlock = block.number;
6702+
uint256 withdrawalAmount = depositAmount / 6;
6703+
for(uint256 i = 0; i < 5; i++) {
6704+
(
6705+
QueuedWithdrawalParams[] memory queuedWithdrawalParams,
6706+
Withdrawal memory withdrawal,
6707+
bytes32 withdrawalRoot
6708+
) = _setUpQueueWithdrawalsSingleStrat({
6709+
staker: defaultStaker,
6710+
withdrawer: defaultStaker,
6711+
strategy: strategyMock,
6712+
depositSharesToWithdraw: withdrawalAmount
6713+
});
6714+
cheats.prank(defaultStaker);
6715+
delegationManager.queueWithdrawals(queuedWithdrawalParams);
6716+
cheats.roll(startBlock + i + 1);
6717+
}
6718+
6719+
// Warp to completion time for the first 2 withdrawals
6720+
// First withdrawal queued at startBlock. Second queued at startBlock + 1
6721+
cheats.roll(startBlock + 1 + delegationManager.minWithdrawalDelayBlocks() + 1);
6722+
6723+
// Get slashable shares
6724+
uint256 slashableSharesInQueue = delegationManager.getSlashableSharesInQueue(defaultOperator, strategyMock);
6725+
assertEq(slashableSharesInQueue, depositAmount/6 * 3, "slashable shares in queue should be 3/6 of the deposit amount");
6726+
6727+
// Slash all of operator's shares
6728+
_setOperatorMagnitude(defaultOperator, strategyMock, 0);
6729+
cheats.prank(address(allocationManagerMock));
6730+
cheats.expectEmit(true, true, true, true, address(delegationManager));
6731+
emit OperatorSharesDecreased(
6732+
defaultOperator,
6733+
address(0),
6734+
strategyMock,
6735+
depositAmount / 6 // 1 withdrawal not queued so decreased
6736+
);
6737+
cheats.expectEmit(true, true, true, true, address(delegationManager));
6738+
emit OperatorSharesBurned(
6739+
defaultOperator,
6740+
strategyMock,
6741+
depositAmount / 6 * 4 // 4 parts are burned
6742+
);
6743+
delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, 0);
6744+
6745+
// Assert slashable shares
6746+
slashableSharesInQueue = delegationManager.getSlashableSharesInQueue(defaultOperator, strategyMock);
6747+
assertEq(slashableSharesInQueue, 0);
6748+
}
6749+
65426750
/**
65436751
* @notice Verifies that `DelegationManager.burnOperatorShares` properly decreases the delegated `shares` that the operator
65446752
* who the `defaultStaker` is delegated to has in the strategies

0 commit comments

Comments
 (0)