Sparkn

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

Funds get stuck at contract because of not implementing correct transfer functions for fee on transfer tokens

Summary

If fee-on-transfer tokens (such as USDT and USDC can activate fees) are used as token, funds will get stuck at contract.

Vulnerability Details

Protocol planning to use USDT, and USDC as shown by natspec:

@notice General ERC20 stable coin tokens, e.g. JPYC, USDC, USDT, DAI, etc, are suppsoed to be used in SPARKN.

These tokens can activate fees, and transfers inside Distributor.sol does not account for that as shown below:

// check if totalPercentage is correct
if (totalPercentage != (10000 - COMMISSION_FEE)) {
revert Distributor__MismatchedPercentages();
}
IERC20 erc20 = IERC20(token);
uint256 totalAmount = erc20.balanceOf(address(this));
// if there is no token to distribute, then revert
if (totalAmount == 0) revert Distributor__NoTokenToDistribute();
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;
}
}
// send commission fee as well as all the remaining tokens to STADIUM_ADDRESS to avoid dust remaining
_commissionTransfer(erc20);
...
function _commissionTransfer(IERC20 token) internal {
token.safeTransfer(STADIUM_ADDRESS, token.balanceOf(address(this)));
}

Which means in the best case scenario there won't be enough fee left in the contract to transfer STADIUM_ADDRESS, and in the worst case scenario, (which is very likely) during for loop contracts balance will reach 0 because of token's fee payment and the next transfer won't occur, hence it will revert.

Because of requirement:

// check if totalPercentage is correct
if (totalPercentage != (10000 - COMMISSION_FEE)) {
revert Distributor__MismatchedPercentages();

totalPercentage has to be exactly 9500 (%95), if fee percentage by token is more than %5, funds will stuck on contract. If less than that amount, then STADIUM_ADDRESS will receive less fees than expected by protocol.

Impact

Funds can stuck in contract without a way to withdraw it. Hence I consider this as high severity.

Tools Used

Manual Review

Recommendations

Although normally it is not best practice, since owner is trusted and protocol is right now semi-centralized, doing following can prevent this issue to happen:

  • Create totalPercentage mapping for every token address.

  • Make these variables changeable by owner.

  • In case of USDT and USDC changed their fee variable, change their totalPercentage accordingly. ( For example if USDT decided to take %10 fee, than make it's totalPercentage 8500 instead of 9500 because %10 of the amount will go to the token transfer fees. )

Support

FAQs

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

Give us feedback!