Sablier

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

The `SablierV2LockupDynamic::_calculateStreamedAmount` could be given a Zero segment to the `SablierV2LOckupDynamic::_calculateStreamedAmountForOneSegment` function resulting in panic

Summary

The SablierV2LockupDynamic::_calculateStreamedAmountForOneSegment is meant to calculate for 1 segment, but the SablierV2LockupDynamic::_calculateStreamedAmount passes any segment less than 1 to it, including zero. And the function SablierV2LockupDynamic::_calculateStreamedAmountForOneSegment is not designed to handle a zero segment which ends up in a panic error.

Vulnerability Details

The issue starts with the SablierV2LockupDynamic::_calculateStreamedAmount checking for segment.length in

if (_segments[streamId].length > 1) {
// If there is more than one segment, it may be required to iterate over all of them.
return _calculateStreamedAmountForMultipleSegments(streamId);
} else {
// Otherwise, there is only one segment, and the calculation is simpler.
return _calculateStreamedAmountForOneSegment(streamId);
}

And not accounting for a zero segment, which is possible to occur before segment[streamId] reaches 1.

Impact

It could lead to a panic error when a user try to see their streamed amount when the segment is still at zero. Depending on time before a segment appear, users could keep spamming the function and lead to network congestion

POC
function test_StreamedAmountOf_EmptySegments()
external
givenNotNull
givenStreamHasNotBeenCanceled
givenStatusStreaming
whenStartTimeInThePast
{
// Simulate the passage of time.
vm.warp({ newTimestamp: defaults.START_TIME() + 2000 seconds });
// Create an empty array of segments.
LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](0);
// Create the stream with no segments.
uint256 streamId = createDefaultStreamWithSegments(segments);
// Expect an error when calling streamedAmountOf due to no segments.
try lockupDynamic.streamedAmountOf(streamId) {
revert("Expected error due to empty segments");
} catch (bytes memory reason) {
// Ensure that the error is due to the empty segments array.
assertEq(reason, "No segments available", "Expected error due to empty segments");
}
}

Tools Used

manual review

Recommendations

Add a requirement for segment to be more than 0 in the SablierV2LockupDynamic::_calculateStreamedAmountForOneSegment function

function _calculateStreamedAmountForOneSegment(uint256 streamId) internal view returns (uint128) {
unchecked {
// Ensure there is at least one segment.
+ require(_segments[streamId].length > 0, "No segments available");
...
Updates

Lead Judging Commences

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

Support

FAQs

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