Summary
There is no validation on the amount of prize tokens in the proxy address upon distribution, meaning malicious organizers can pay as little as 1 wei for a contest.
Vulnerability Details
The check in Distributor#_distribute only checks that the addresses token balance is non-zero:
File: src\Distributor.sol
138: IERC20 erc20 = IERC20(token);
139: uint256 totalAmount = erc20.balanceOf(address(this));
140:
141:
142: if (totalAmount == 0) revert Distributor__NoTokenToDistribute();
This means that supporters may be mislead about the amount of funds they are earning.
Impact
Malicious organizer can underpay supporters.
Tools Used
Manual review
Recommendations
In ProxyFactory#setContest, add parameters to specify the token used for the prizes, and the total prize amount for the contest. Also, handle the transfer of tokens from the organizer to the proxy address to enforce the proper prizes are indeed sent to the contract.
File: src/ProxyFactory.sol
- function setContest(address organizer, bytes32 contestId, uint256 closeTime, address implementation)
+ function setContest(address organizer, bytes32 contestId, uint256 closeTime, address implementation, uint256 prizeAmount, address prizeToken)
public
onlyOwner
{
+ require(whitelistedTokens[prizeToken], "not whitelisted");
if (organizer == address(0) || implementation == address(0)) revert ProxyFactory__NoZeroAddress();
if (closeTime > block.timestamp + MAX_CONTEST_PERIOD || closeTime < block.timestamp) {
revert ProxyFactory__CloseTimeNotInRange();
}
bytes32 salt = _calculateSalt(organizer, contestId, implementation);
if (saltToCloseTime[salt] != 0) revert ProxyFactory__ContestIsAlreadyRegistered();
saltToCloseTime[salt] = closeTime;
emit SetContest(organizer, contestId, closeTime, implementation);
+ IERC20(prizeToken).safeTransferFrom(organizer, getProxyAddress(salt, implementation), prizeAmount);
}