Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Withdrawal Struct Not Updated During Finalization When sharesToWithdraw Exceeds sharesRemaining

Summary

The _finalizeWithdrawals function is responsible for finalizing the accounting of queued withdrawals in the system after withdrawals are processed. However, when sharesToWithdraw > sharesRemaining, as the queuedWithdrawals[i] struct is not updated to reflect the withdrawal of all remaining shares.

Vulnerability Details

when sharesToWithdraw > sharesRemaining, the function processes a full withdrawal for the current entry in the queuedWithdrawals array and advances to the next withdrawal (indexOfNextWithdrawal = i + 1).

if (sharesRemaining > sharesToWithdraw) {
// partially finalize withdrawal
queuedWithdrawals[i] = Withdrawal(
uint128(sharesRemaining - sharesToWithdraw),
uint128(
queuedWithdrawals[i].partiallyWithdrawableAmount +
_getStakeByShares(sharesToWithdraw)
)
);
indexOfNextWithdrawal = i;
withdrawalBatches.push(
WithdrawalBatch(uint128(i - 1), uint128(_getStakeByShares(1 ether)))
);
} else {
// here not updated
indexOfNextWithdrawal = i + 1;
withdrawalBatches.push(
WithdrawalBatch(uint128(i), uint128(_getStakeByShares(1 ether)))
);
}

However, the queuedWithdrawals[i] struct is not updated to reflect that the remaining shares have been fully withdrawn. As a result:

The sharesRemaining in the queuedWithdrawals[i] struct is left unchanged, inaccurately indicating that some shares are still available for withdrawal.

Impact

The contract's internal state will not accurately reflect the actual number of shares left for withdrawal.

Tools Used

manual review

Recommendations

When sharesToWithdraw exceeds sharesRemaining, update the struct to set sharesRemaining to 0 and adjust partiallyWithdrawableAmount accordingly.

if (sharesRemaining > sharesToWithdraw) {
queuedWithdrawals\[i] = Withdrawal(
uint128(sharesRemaining - sharesToWithdraw),
uint128(
queuedWithdrawals\[i].partiallyWithdrawableAmount +
\_getStakeByShares(sharesToWithdraw)
)
);
indexOfNextWithdrawal = i;
withdrawalBatches.push(
WithdrawalBatch(uint128(i - 1), uint128(\_getStakeByShares(1 ether)))
);
} else {
queuedWithdrawals[i].sharesRemaining = 0;
queuedWithdrawals[i].partiallyWithdrawableAmount += _getStakeByShares(sharesRemaining);
indexOfNextWithdrawal = i + 1;
withdrawalBatches.push(
WithdrawalBatch(uint128(i), uint128(_getStakeByShares(1 ether)))
);

}

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.