Flow

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

Potential Arithmetic Overflow in SablierFlow.depletionTimeOf() Due to Type Casting

Summary

The depletionTimeOf function in SablierFlow contract contains arithmetic operations where intermediate expressions return a lower-order uint type (uint40) than the target type (uint256), which could potentially lead to arithmetic overflow due to implicit type casting.

Vulnerability Details

// Location: src/SablierFlow.sol#L53-L101
function depletionTimeOf(uint256 streamId) external view returns (uint256 depletionTime) {
// ...
unchecked {
uint256 solvencyAmount = balanceScaled - snapshotDebtScaled + oneMVTScaled;
uint256 solvencyPeriod = solvencyAmount / ratePerSecond;
if (solvencyAmount % ratePerSecond == 0) {
// First problematic operation
depletionTime = _streams[streamId].snapshotTime + solvencyPeriod;
} else {
// Second problematic operation
depletionTime = _streams[streamId].snapshotTime + solvencyPeriod + 1;
}
}
}

The issue occurs because:

  1. _streams[streamId].snapshotTime is of type uint40

  2. The arithmetic operations are performed in an unchecked block

  3. When adding uint40 + uint256, the intermediate expression returns uint40 before being assigned to uint256

  4. This could lead to unexpected overflow if solvencyPeriod is large enough

Impact

If solvencyPeriod is large enough, the intermediate uint40 calculation could overflow before being stored in the uint256 depletionTime

This could lead to incorrect depletion time calculations

The impact is somewhat mitigated by the fact that solvencyPeriod would need to be very large to trigger the overflow

The code is within an unchecked block which makes it more concerning

Tools Used

slither .

## pess-potential-arithmetic-overflow
Impact: Medium
Confidence: Medium
* [ ] ID-22
[SablierFlow.depletionTimeOf(uint256)]() contains integer variables whose type is larger than the type of one of its intermediate expressions. Consider casting sub expressions explicitly as they might lead to unexpected overflow:
In `[depletionTime = _streams[streamId].snapshotTime + solvencyPeriod]()` intermidiate expressions returns type of lower order:
`REF_144 + solvencyPeriod` returns uint40, but the type of the resulting expression is uint256.
In `[depletionTime = _streams[streamId].snapshotTime + solvencyPeriod + 1]()` intermidiate expressions returns type of lower order:
`REF_146 + solvencyPeriod` returns uint40, but the type of the resulting expression is uint256.
`... + 1` returns uint40, but the type of the resulting expression is uint256.
src/SablierFlow\.sol#L53-L101

manuel code review

Recommendations:

Explicitly cast snapshotTime to uint256 before performing arithmetic:

function depletionTimeOf(uint256 streamId) external view returns (uint256 depletionTime) {
unchecked {
uint256 solvencyAmount = balanceScaled - snapshotDebtScaled + oneMVTScaled;
uint256 solvencyPeriod = solvencyAmount / ratePerSecond;
if (solvencyAmount % ratePerSecond == 0) {
depletionTime = uint256(_streams[streamId].snapshotTime) + solvencyPeriod;
} else {
depletionTime = uint256(_streams[streamId].snapshotTime) + solvencyPeriod + 1;
}
}
}

Consider removing the unchecked block to ensure safer arithmetic operations:

if (solvencyAmount % ratePerSecond == 0) {
depletionTime = uint256(_streams[streamId].snapshotTime) + solvencyPeriod;
} else {
depletionTime = uint256(_streams[streamId].snapshotTime) + solvencyPeriod + 1;
}
Updates

Lead Judging Commences

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

Support

FAQs

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