Sablier

Sablier
DeFiFoundry
53,440 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect Streamed Amount Calculation Leading to Fund Lockup

Summery

the bug is from the improper handling of the streamed amount calculation when the elapsed time exceeds the total duration.
This results in a scenario where the calculated streamedAmount can exceed the depositedAmount, leading to a fallback mechanism that returns an incorrect amount, potentially locking the funds and preventing the recipient from withdrawing the correct amount

Vulnerability Details

Here is the Vulnerable Line:

if (streamedAmount.gt(depositedAmount)) {
return _streams[streamId].amounts.withdrawn;
}

The function _calculateStreamedAmount is calculates the amount of tokens that have been streamed s based on the elapsed time and the formula used is:

UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration);
UD60x18 depositedAmount = ud(_streams[streamId].amounts.deposited);
UD60x18 streamedAmount = elapsedTimePercentage.mul(depositedAmount);

This calculates the streamed amount as a fraction of the deposited amount based on the elapsed time
So the flaw here arises from the edge case in the calculation where streamedAmount can exceed depositedAmount due to an arithmetic or logic error.

  • here is a scenario of attack :

  • let’s say Alice wants to stream 1000 DAI to Bob over 10 days now Alice creates a stream by depositing 1000 DAI, and the stream is set to end in 10 days.

  • so during the Stream the contract calculates how much DAI Bob should have received so far based on elapsed time , For example, on day 5, Bob should have 500 DAI streamed to him.

  • the contract mistakenly calculates that more than 1000 DAI have been streamed and this can happen if the elapsed time percentage or the deposited amount is incorrectly handled.

  • Instead of returning the correct streamed amount, the contract checks if streamedAmount exceeds depositedAmount and falls back to returning the withdrawn amount and this condition is lead to Bob being unable to withdraw the correct amount or any amount at all if the calculation locks the funds.

  • here is the details scenario :

Here is an example scenario :

  • Alice Creates the Stream so Alice calls createWithDurations to start streaming 1000 DAI to Bob over 10 days

  • The stream starts correctly, and startTime, cliffTime, and endTime are set properly.

  • Day 5 Bob tries to withdraw his streamed DAI.

  • The contract calculates as :

UD60x18 elapsedTime = ud(block.timestamp - startTime); // e.g., 5 days
UD60x18 totalDuration = ud(endTime - startTime); // 10 days
UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration); // 0.5
UD60x18 depositedAmount = ud(1000); // 1000 DAI
UD60x18 streamedAmount = elapsedTimePercentage.mul(depositedAmount); // 0.5 * 1000 = 500 DAI
  • so If an error occurs and streamedAmount mistakenly becomes greater than 1000 the fallback logic will trigger

  • The contract checks is :

if (streamedAmount.gt(depositedAmount)) {
return _streams[streamId].amounts.withdrawn;
}
  • If streamedAmount is greater than 1000, it returns the amount Bob has already withdrawn which might be 0 if he hasn’t withdrawn anything yet

Impact

can lock funds if streamedAmount calculation is incorrect

Tools Used

Manual review

Recommendations

Need to ensure that the streamed amount does not exceed the deposited amount:

if (streamedAmount.gt(depositedAmount)) {
revert("Streamed amount exceeds deposited amount");
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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