Sparkn

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

Potential Fund Loss for Sponsors

Summary

In situations where there are no supporters or if a contest is canceled, sponsors could lose up to 5% of their funds.

Vulnerability Details

Proof of Concept (POC): Fund Loss for Sponsors due to Cancellation

  • Owner initiates a new Contest.

  • Sponsors fund the contest.

  • After the expiration period, no submission has been filled and supporters did not join.

  • The owner calls the deployProxyAndDistributeByOwner or the organizer calls the deployProxyAndDistribute function by putting the sponsors addresses and their correspnding percentages as winners so that they can recover their funds.

  • The _distribute function in the Distributor contract takes a 5% commission fee, leading to losses for the sponsor.

Impact

  • The sponsors are now in loss. A sponsor can lose up to 5% of his initial funding if he is the only sponsor of the contest.

Tools Used

Manual review

Recommendations

  • Add a new _distributeBackToSponsors function that does not take fees in case some funds need to be returned to sponsors :

function _distributeBackToSponsors(address token, address[] memory sponsors, uint256[] memory percentages, bytes memory data)
internal
{
// token address input check
if (token == address(0)) revert Distributor__NoZeroAddress();
if (!_isWhiteListed(token)) {
revert Distributor__InvalidTokenAddress();
}
// sponsors and percentages input check
if (sponsors.length == 0 || sponsors.length != percentages.length) revert Distributor__MismatchedArrays();
uint256 percentagesLength = percentages.length;
uint256 totalPercentage;
for (uint256 i; i < percentagesLength;) {
totalPercentage += percentages[i];
unchecked {
++i;
}
}
// comment the following line
// We do not account for COMMISSION_FEE
// 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 sponsorsLength = sponsors.length; // cache length
for (uint256 i; i < sponsorsLength;) {
uint256 amount = totalAmount * percentages[i] / BASIS_POINTS;
erc20.safeTransfer(sponsors[i], amount);
unchecked {
++i;
}
}
// send commission fee as well as all the remaining tokens to STADIUM_ADDRESS to avoid dust remaining
_commissionTransfer(erc20);
emit Distributed(token, sponsors, percentages, data);
}

Then add an onlyOwner distributeBackToSponsors function in ProxyFactory contract that calls this function using the proxy.

  • A simpler idea would be to add a uint256 commission parameter to the _distribute function. this way the caller can specify the commission value in case of sponsors, but this also means that Organizer have access to this parameter.

Support

FAQs

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

Give us feedback!