sherlock-audit / 2022-11-nounsdao-judging

4 stars 0 forks source link

Zarf - Payer’s funds might be permanently locked in certain cases #40

Closed sherlock-admin closed 1 year ago

sherlock-admin commented 1 year ago

Zarf

high

Payer’s funds might be permanently locked in certain cases

Summary

In some cases it might be impossible for the payer to cancel the stream and retrieve the funds which were not yet entitled to the receiver. Due to the same root cause, it might be impossible for the payer to withdraw any amount of tokens which were sent to the stream contract on top of the hardcoded tokenAmount.

Vulnerability Detail

The only way for the payer to retrieve the stream specific funds in the contract is through the cancel() function (any other non-stream specific funds can be retrieved using rescueERC20()). There are two cases in which the payer would like to retrieve his funds:

  1. In case he cancels the stream before the stream has ended. All the funds which were not yet entitled to the recipient will still belong to the payer.
  2. In case, by mistake, the payer sent additional stream specific tokens on top of the hardcoded tokenAmount and would like to withdraw those from the contract.

In both cases the payer has to cancel the stream using cancel(). However, if the recipient is still entitled to some of the funds in the stream (as he/she did not withdraw them yet), they will be withdrawn in the following line:

https://github.com/sherlock-audit/2022-11-nounsdao/blob/main/src/Stream.sol#L249

According to the docs, Streams support the USDC token. However, USDC supports blacklisting, which could block certain addresses from both sending and receiving USDC:

https://github.com/centrehq/centre-tokens/blob/0d3cab14ebd133a83fc834dbd48d0468bdf0b391/contracts/v1/FiatTokenV1.sol#L272-L282

Therefore, if a recipient gets blacklisted on USDC (e.g. by interacting with Tornado Cash on purpose), the cancel() function will revert and the payer is unable to retrieve the funds he’s/she’s entitled to upon cancellation, or any extra stream specific funds which were sent to the contract.

Impact

If a stream gets funded after the stream is created, there is no way to block any funds on top of the hardcoded tokenAmount. Therefore, if the payer accidentally sends too much tokens, a recipient might act maliciously and perform certain actions to be placed on the USDC blacklist.

Let’s suppose this happens just after the stream started, when the recipient is entitled to a few wei. However, the few wei lost might not be an issue for the recipient compared to amount of damage the recipient could cause by getting blacklisted. In that case, a potentially large amount of USDC which was sent by the funder will be permanently locked in the contract. Hence, we deem the risk as high.

Code Snippet

https://github.com/sherlock-audit/2022-11-nounsdao/blob/main/src/Stream.sol#L237-L259

Tool used

Manual Review

Recommendation

Although it will lead to additional gas costs, it is recommended in the cancel() function to keep track of the funds to which the payer and recipient are entitled to whenever one of both cancel’s the stream. An additional function can be created to subsequently withdraw the funds of either the payer or recipient. This way the token transfer to the payer will not be impacted if the token transfer to the recipient reverts.

Duplicate of #37