DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: low
Invalid

Incorrect Handling of Partial Withdrawals in _unstakeVested Function

Summary

the _unstakeVested function does not correctly handle scenarios where a portion of the tokens has already been withdrawn from a vested stream before the stream is canceled. This could lead to incorrect unstaking amounts, resulting in inconsistencies in the contract's state and potential errors in reward calculations.

Vulnerability Details

The _unstakeVested function is responsible for managing the unstaking of vested tokens when a Sablier stream is canceled. The function currently assumes that the full vested amount is available for unstaking, without accounting for any partial withdrawals that may have occurred before the stream was canceled.

function _unstakeVested(address streamOwner, uint256 _streamID, uint256 amount) internal {
NFTData storage data = _streamIDs[streamOwner][_streamID];
DepositReceipt storage dr = deposits[streamOwner][data.epoch];
if (amount > data.amount) revert InvalidAmount();
dr.vestedStaked -= amount;
totalStaked -= amount;
totalVestedStaked -= amount;
userData[streamOwner].totalStaked -= amount;
if (dr.vestedStaked == 0 && dr.staked == 0) {
delete deposits[streamOwner][data.epoch];
_activeDeposits[streamOwner].remove(data.epoch);
}
// Transfer the remaining stream back to the user
sablier.transferFrom(address(this), streamOwner, _streamID);
}

the function directly reduces the vestedStaked amount by the provided amount without checking whether some of the vested tokens have already been withdrawn. This lead to overestimating the available balance and attempting to unstake more tokens than are actually present.

Impact

1: The user's balance and the contract's state will be incorrectly updated, leading to discrepancies between the actual and recorded amounts.

Tools Used

Manaul review

Recommendations

1: Before unstaking, the function should check the current balance of the stream, considering any prior withdrawals.

uint128 withdrawnAmount = sablier.getWithdrawnAmount(_streamID);
uint128 availableAmount = depositedAmount - withdrawnAmount;
if (amount > availableAmount) revert InvalidAmount();

2: The function should adjust the unstaking amount based on the actual remaining balance, ensuring that only the tokens still in the stream are unstaked.

3: Implement a full check of the stream’s current state, including any modifications, before proceeding with the unstake.

Updates

Lead Judging Commences

inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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