It doesn't handle fee-on-transfer/deflationary tokens
Summary
Although the protocol currently doesn't have fee-on-transfer or rabasing tokens in on-chain context, since StreamFactory.createStream(...) is proposed by users, it is not guaranteed fee-to-transfer/deflationary tokens won't be used to transfer in stream from payers to recipients in the future.
Vulnerability Detail
The streaming solution consists of Streamer and Token Buyer. After StreamFactory.createStream(...) creates a proposal with Streamer, the user as the Payer can submit a call of Payer.sendOrRegisterDebt(...) and register debt. https://github.com/nounsDAO/token-buyer/blob/main/src/Payer.sol#L100-L118
Then the Payer can call Payer.payBackDebt(...) to fund the stream asynchronously. As can be seen in the following, Payer.payBackDebt(...) doesn't check the balance after the execution of paymentToken.safeTransfer(_debtAccount, amount) or paymentToken.safeTransfer(_debtAccount, _debtAmount) and the debt amount is calculated by dequeuing from the registered debt queue before the transfer. When in fee-on-transfer/deflationary tokens case, the Stream contract will receive the amount of tokens less than the amount declared in the proposal of StreamFactory.createStream(...). https://github.com/nounsDAO/token-buyer/blob/main/src/Payer.sol#L139-L191
In Token Buyer, check the balance after the execution of paymentToken.safeTransfer(_debtAccount, amount) or paymentToken.safeTransfer(_debtAccount, _debtAmount) in Payer.payBackDebt(...);
zimu
medium
It doesn't handle fee-on-transfer/deflationary tokens
Summary
Although the protocol currently doesn't have fee-on-transfer or rabasing tokens in on-chain context, since
StreamFactory.createStream(...)
is proposed by users, it is not guaranteed fee-to-transfer/deflationary tokens won't be used to transfer in stream from payers to recipients in the future.Vulnerability Detail
The streaming solution consists of Streamer and Token Buyer. After
StreamFactory.createStream(...)
creates a proposal with Streamer, the user as the Payer can submit a call ofPayer.sendOrRegisterDebt(...)
and register debt. https://github.com/nounsDAO/token-buyer/blob/main/src/Payer.sol#L100-L118Then the Payer can call
Payer.payBackDebt(...)
to fund the stream asynchronously. As can be seen in the following,Payer.payBackDebt(...)
doesn't check the balance after the execution ofpaymentToken.safeTransfer(_debtAccount, amount)
orpaymentToken.safeTransfer(_debtAccount, _debtAmount)
and the debt amount is calculated by dequeuing from the registered debt queue before the transfer. When in fee-on-transfer/deflationary tokens case, the Stream contract will receive the amount of tokens less than the amount declared in the proposal ofStreamFactory.createStream(...)
. https://github.com/nounsDAO/token-buyer/blob/main/src/Payer.sol#L139-L191After the stop time, the recipient would finally withdraw and receive less amount of tokens than the amount declared in the proposal. https://github.com/sherlock-audit/2022-11-nounsdao/blob/main/src/Stream.sol#L213-L228
Impact
The recipient will receive less amount of tokens than the amount declared in the proposal.
Code Snippet
https://github.com/nounsDAO/token-buyer/blob/main/src/Payer.sol#L100-L118 https://github.com/nounsDAO/token-buyer/blob/main/src/Payer.sol#L139-L191 https://github.com/sherlock-audit/2022-11-nounsdao/blob/main/src/Stream.sol#L213-L228
Tool used
Manual Review
Recommendation
paymentToken.safeTransfer(_debtAccount, amount)
orpaymentToken.safeTransfer(_debtAccount, _debtAmount)
inPayer.payBackDebt(...)
;to