Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: low
Valid

ERC20 tokens with blackList can cause DoS attack and can prevent the #Distributor.sol contract from sending the rewards

Summary

ERC20 tokens with blackList can prevent the Distributor contract form sending the reward to the winners .

Vulnerability Details

When distribution the safeTransfer of OpenZeppelin SafeERC20Upgradeable (inheriting from SafeERC20) is used which deals with the multiple ways in which different ERC-20 (BEP-20) tokens indicate the success/failure of a token transfer.
Nevertheless, there is addition scenario that will prevent the all function from distributing the reward to the winners

  • the ERC20 tokens that are implementing a blacklist.
    In this scenario, the reward token is implemented with a blacklist (also known as blocklist).
    -DOS with the reward token being an ERC20-compatible ERC777 token as there is nothing says in the README that the ERC-777 token is not allowed to be used .

Because this is common for tokens on the Ethereum network (e.g. USDC/USDT implementing blacklist/blocklist; See: https://github.com/d-xo/weird-erc20) this is a scenario also possible for the tokens .

the DoS scenario if the reward token is ERC20 token that implements a blocklist can be :

  1. the winner is put in the token blacklist .

  2. the distributor try to send the rewards to the winners but this function always reverts , because of the users is on the blackList.
    the DoS scenario if the reward token is an ERC20-compatible ERC777 token :

  3. one of the winners acts as an "ERC777 recipient" which can either accept/reject tokens that are transferred to it .

  4. when the tokens get transferred to the malicious winner he will reject the token transfer as (ERC777 token calls tokensReceived function of receiving smart contract to finalize the token transfer which reverts)

the function _distribute() will revert during sending the funds to the winners .

uint256 winnersLength = winners.length; // cache length
for (uint256 i; i < winnersLength;) {
uint256 amount = totalAmount * percentages[i] / BASIS_POINTS;
erc20.safeTransfer(winners[i], amount);
unchecked {
++i;
}

Impact

the DoS prevent the winners from getting their reward which cause a loss of funds of the users.

Tools Used

manual review

Recommendations

Use a withdrawal pattern ("pull over push") instead of directly send the reward to the winners. See: https://fravoll.github.io/solidity-patterns/pull_over_push.html for details. This way the function _distribute() will not get into a state of DOS.
by adding a function withdraw to allow the winners to claim their rewards , and creating a mapping from a winner to the balance

mapping(address winner => uint256 balance ) public balances ;
function withdraw(uint256 amount) external {
balances [msg.sender] -= amount ;
erc20.safeTransfer(msg.sender , amount);
}

Support

FAQs

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