Flow

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

Zero Rate Per Second Event Emission Inconsistency in the create function

Summary

An inconsistency has been identified in the stream event emission system where streams created with zero rate per second (RPS) are effectively paused but do not emit the appropriate pause event. This creates a discrepancy between the stream's effective state and the emitted events.

Vulnerability Details

The vulnerability occurs when streams are created with zero RPS. While the system functionally treats these streams as paused, it fails to emit the corresponding pause event. This creates an inconsistency with other pause scenarios:

  1. Stream Creation with Zero RPS (_create()):

function _create(
address sender,
address recipient,
UD21x18 ratePerSecond,
IERC20 token,
bool transferable
) internal returns (uint256 streamId) {
// Zero RPS is allowed, creating an effectively paused stream
_streams[streamId] = Flow.Stream({
ratePerSecond: ratePerSecond,
// ... other fields
});
// Only emits creation event, no pause event
emit ISablierFlow.CreateFlowStream({
streamId: streamId,
sender: sender,
recipient: recipient,
ratePerSecond: ratePerSecond,
token: token,
transferable: transferable
});
}
  1. Explicit Pause (_pause()):

function _pause(uint256 streamId) internal {
_adjustRatePerSecond({ streamId: streamId, newRatePerSecond: ud21x18(0) });
// Correctly emits pause event
emit ISablierFlow.PauseFlowStream({
streamId: streamId,
sender: _streams[streamId].sender,
recipient: _ownerOf(streamId),
totalDebt: _totalDebtOf(streamId)
});
}
  1. Stream State Check in _restart():

function _restart(uint256 streamId, UD21x18 ratePerSecond) internal {
// System considers zero RPS as paused
if (_streams[streamId].ratePerSecond.unwrap() != 0) {
revert Errors.SablierFlow_StreamNotPaused(streamId);
}
// ... rest of the function
}

Core Issues:

Event Emission Inconsistency:

  • Creating a stream with RPS = 0: Only emits CreateFlowStream

  • Pausing a stream explicitly: Emits PauseFlowStream

  • Both scenarios result in the same effective state (paused)

State-Event Mismatch:

  • System treats zero RPS as paused state

  • Creation with zero RPS doesn't emit events matching this state

  • Creates discrepancy between state and event history

Impact

  • Off-chain systems tracking pause events will miss initially paused streams

  • Inconsistent event history for effectively identical state

  • Systems relying on pause events for state management will fail

  • Monitoring systems may report incorrect stream states

Tools Used

Manual code review

Recommendations

Add pause event emission for zero RPS creation:

function _create(
address sender,
address recipient,
UD21x18 ratePerSecond,
IERC20 token,
bool transferable
) internal returns (uint256 streamId) {
// Create the stream
streamId = nextStreamId;
_streams[streamId] = Flow.Stream({
ratePerSecond: ratePerSecond,
// ... other fields
});
// Emit creation event
emit ISablierFlow.CreateFlowStream({
streamId: streamId,
sender: sender,
recipient: recipient,
ratePerSecond: ratePerSecond,
token: token,
transferable: transferable
});
// If zero RPS, emit pause event to maintain consistency
if (ratePerSecond.unwrap() == 0) {
emit ISablierFlow.PauseFlowStream({
streamId: streamId,
sender: sender,
recipient: recipient,
totalDebt: 0
});
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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