Platform: Code4rena
Start Date: 27/04/2023
Pot Size: $90,500 USDC
Total HM: 4
Participants: 43
Period: 7 days
Judge: GalloDaSballo
Id: 233
League: ETH
Rank: 16/43
Findings: 1
Award: $1,443.93
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: juancito
Also found by: MiloTruck, Ruhum, SpicyMeatball, bin2chen, evmboi32, pontifex, sashik_eth, volodya, yjrwkk
1443.9307 USDC - $1,443.93
Users can avoid getting their queuedWithdrawal slashed because of the wrong implementation.
Let's take a look at the following code snippet from StrategyManager#slashQueuedWithdrawal
.
// keeps track of the index in the `indicesToSkip` array uint256 indicesToSkipIndex = 0; uint256 strategiesLength = queuedWithdrawal.strategies.length; for (uint256 i = 0; i < strategiesLength;) { // check if the index i matches one of the indices specified in the `indicesToSkip` array if (indicesToSkipIndex < indicesToSkip.length && indicesToSkip[indicesToSkipIndex] == i) { unchecked { ++indicesToSkipIndex; } } else { if (queuedWithdrawal.strategies[i] == beaconChainETHStrategy){ //withdraw the beaconChainETH to the recipient _withdrawBeaconChainETH(queuedWithdrawal.depositor, recipient, queuedWithdrawal.shares[i]); } else { // tell the strategy to send the appropriate amount of funds to the recipient queuedWithdrawal.strategies[i].withdraw(recipient, tokens[i], queuedWithdrawal.shares[i]); } unchecked { ++i; } } }
Now let's say we want to skip only the first strategy because it always reverts on withdraw. We will do this be calling slashQueuedWithdrawal
with indicesToSkip = [0]
. If we follow the code we can see that in the first iteration i=0
and indicesToSkipIndex=0
. We enter the if part since the condition is true (indicesToSkip[0] == 0). This will increase the indicesToSkipIndex
to 1.
Now in second iteration we have indicesToSkipIndex = 1
and i = 0
. The if part is not true in this iteration so we enter the else part of the conditional statement and essentially try to withdraw from the strategy[0]
that we wanted to skip.
User can set such an array of strategies when queueing withdrawal that withdrawing from the first strategy always fails. This way his queued withdrawal cannot get slashed.
Put the ++i
statement outside of else part.
// keeps track of the index in the `indicesToSkip` array uint256 indicesToSkipIndex = 0; uint256 strategiesLength = queuedWithdrawal.strategies.length; for (uint256 i = 0; i < strategiesLength;) { // check if the index i matches one of the indices specified in the `indicesToSkip` array if (indicesToSkipIndex < indicesToSkip.length && indicesToSkip[indicesToSkipIndex] == i) { unchecked { ++indicesToSkipIndex; } } else { if (queuedWithdrawal.strategies[i] == beaconChainETHStrategy){ //withdraw the beaconChainETH to the recipient _withdrawBeaconChainETH(queuedWithdrawal.depositor, recipient, queuedWithdrawal.shares[i]); } else { // tell the strategy to send the appropriate amount of funds to the recipient queuedWithdrawal.strategies[i].withdraw(recipient, tokens[i], queuedWithdrawal.shares[i]); } - unchecked { - ++i; - } } + unchecked { + ++i; + } }
DoS
#0 - c4-pre-sort
2023-05-09T13:09:19Z
0xSorryNotSorry marked the issue as duplicate of #205
#1 - c4-judge
2023-06-08T12:23:27Z
GalloDaSballo changed the severity to 3 (High Risk)
#2 - c4-judge
2023-06-08T12:23:53Z
GalloDaSballo marked the issue as satisfactory