Sparkn

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

Organizer/Sponsor can get partial refund

Summary

The contracts are designed to be support first meaning that once funded, the sponsor cannot get refund. It is possible in Distributor.sol get partial refund.

Vulnerability Details

Once a contract is deployed, the implementation is used to distribute prizes to winners. The organizer can pass his own address to winners array and 95% to percentages array to get 95% refund.

function _distribute(address token, address[] memory winners, uint256[] memory percentages, bytes memory data)
internal
{
// token address input check
if (token == address(0)) revert Distributor__NoZeroAddress();
if (!_isWhiteListed(token)) {
revert Distributor__InvalidTokenAddress();
}
// winners and percentages input check
if (winners.length == 0 || winners.length != percentages.length) revert Distributor__MismatchedArrays();
uint256 percentagesLength = percentages.length;
uint256 totalPercentage;
for (uint256 i; i < percentagesLength;) {
totalPercentage += percentages[i];
unchecked {
++i;
}
}
// 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);
emit Distributed(token, winners, percentages, data);
}

Impact

The contracts invariants will be broken

Tools Used

Manual review

Recommendations

Add the following:

function _distribute(address token, address[] memory winners, uint256[] memory percentages, bytes memory data)
internal
{
//...
for (uint256 i; i < winnersLength;) {
if(winners[i] == organizerAddress) revert Distributor__InvalidTokenAddress();
unchecked {
++i;
}
}
//...
}

Support

FAQs

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