The withdraw
function assumes a normal ERC20 transfer will be used, but does not properly handle tokens with transfer fees or rebasing mechanics. This can cause accounting discrepancies, locked funds, and unexpected behavior when such tokens are streamed.
Fee-on-transfer and rebasing tokens can lead to inconsistencies between the withdraw
function's amount
parameter and the actual tokens received by the to
address. This breaks internal bookkeeping and can result in lost funds or incorrect balances. The function's assumptions about token behavior create vulnerabilities when used with non-standard ERC20s.
The key issue is in the withdraw
function in SablierFlow.sol
:
For fee-on-transfer tokens, the amount
deducted from _streams[streamId].balance
will be greater than the tokens actually received by to
, since a fee is taken out. This means the stream balance will be decremented by more than the true amount withdrawn.
For rebasing tokens, the token contract balance can change between the safeTransfer
and the balance update. If the token rebases up, the stream's balance will end up lower than expected. If it rebases down, the stream balance will be higher than the contract actually holds.
In both cases, the invariant at the end will fail, reverting the withdraw. Over time, locked funds can accumulate that cannot be withdrawn due to this.
Medium. When used with fee-on-transfer or rebasing tokens, withdraw
will routinely fail due to the broken invariant. User funds can become stuck in the contract. While the admin could allow withdrawals by temporarily removing the invariant check, this requires a high degree of active management and trust in the admin.
Manual code review
For fee-on-transfer tokens, calculate the actual amount received and use that to update internal accounting, rather than the original amount
.
For rebasing tokens, take a balance snapshot before and after the transfer to determine the change, and use this "realized amount" to update the stream balance.
Consider adding warnings or restrictions when creating streams with these token types to prevent users accidentally using incompatible tokens.
Longer-term, explore designs that isolate each stream's balance to limit the impact of individual token issues.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.