Flow

Sablier
FoundryDeFi
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

Loss of precision in the `Helpers::descaleAmount` function, which will lead to a loss of funds.

Relevant GitHub Links

https://github.com/sablier-labs/flow/blob/5b3e293c24f9bf50e73876d67b0981779e865300/src/libraries/Helpers.sol#L59

Summary

A smaller amount divided by a very large value of scaleFactor will always return zero as the result.

Vulnerability Details

When descaling the amount value provided in the Helpers::descaleAmount function, if the difference in number between amount and scaleFactor is so great that dividing amount by sacleFactor results in a value between 0 and 1 ( 0 < result < 1); the result will always be rounded down to zero and the initial amount will be loss:

function descaleAmount(uint256 amount, uint8 decimals) internal pure returns (uint256) {
if (decimals == 18) {
return amount;
}
unchecked {
@> uint256 scaleFactor = 10 ** (18 - decimals);
@> return amount / scaleFactor;
}
}

This function is used in the SablierFlow::_withdraw function to calculate the total debt:

function _withdraw(
uint256 streamId,
address to,
uint128 amount
)
internal
returns (uint128 withdrawnAmount, uint128 protocolFeeAmount)
{
/// ... The rest of code
// Calculate the total debt.
uint256 totalDebtScaled = _ongoingDebtScaledOf(streamId) + _streams[streamId].snapshotDebtScaled;
@> uint256 totalDebt = Helpers.descaleAmount(totalDebtScaled, tokenDecimals);
/// ... The rest of code
}

Regarding to the issue described above, this totalDebt may return an incorrect amount, resulting in a loss of funds or the inability to make a withdrawal.

For example; if amount = 5 and decimals = 10:

  1. With decimals = 10, the function calculates scaleFactor as:
    scaleFactor = 10^(18−10)=10^8=100,000,000

  2. The function then divides amount by scaleFactor:
    result=amount / scaleFactor = 5 / 100,000,000 = 0

Since Solidity uses integer division, the result will truncate any decimals, so the final result is 0.
So the 5 amount of tokens provided by the user will be descaled to 0 amount of token.

Impact

As small amounts cannot be descaled, they cannot be withdrawn either and will remain locked in the contract.

Tools Used

Manual review.

Recommendations

Use libraries like OpenZeppelin’s SafeMath or Solidity’s built-in arithmetic features to handle arithmetic operations safely.

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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