The Pot constructor accepts rewards[] and totalRewards as separate parameters but never validates that sum(rewards[i]) == totalRewards.
If sum(rewards) > totalRewards, the Pot is underfunded — later claimants' transfers will revert. If sum(rewards) < totalRewards, excess tokens are permanently locked with no way to recover them.
Likelihood:
The owner passes totalRewards manually through createContest(). A simple miscalculation or off-by-one error in the frontend or script causes a mismatch.
There is no on-chain check to prevent this, so every contest creation relies on off-chain correctness.
Impact:
If sum(rewards) > totalRewards: the Pot is underfunded. The remainingRewards tracker underflows or the actual token balance runs out. Last claimants cannot receive their rewards.
If sum(rewards) < totalRewards: remainingRewards never reaches 0 even after all claims. Excess tokens sit in the Pot forever with no recovery function.
The closePot function compounds this issue by distributing based on the inflated remainingRewards value.
The following test creates a Pot where the sum of individual rewards (120 ether) exceeds totalRewards (100 ether). The first two players drain the available balance, and the third player's claim reverts because there are not enough tokens remaining.
Add a validation loop in the Pot constructor that sums all individual rewards and requires the total to equal the totalRewards parameter. Also validate that players and rewards arrays have the same length to prevent out-of-bounds access or silently ignored entries.
## Description there are two major problems that comes with the way contests are created using the `ContestManager::createContest`. - using dynamic arrays for `players` and `rewards` leads to potential DoS for the `Pot::constructor`, this is possible if the arrays are too large therefore requiring too much gas - it is not safe to trust that `totalRewards` value supplied by the `manager` is accurate and that could lead to some players not being able to `claimCut` ## Vulnerability Details - If the array of `players` is very large, the `Pot::constructor` will revert because of too much `gas` required to run the for loop in the constructor. ```Solidity constructor(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards) { i_players = players; i_rewards = rewards; i_token = token; i_totalRewards = totalRewards; remainingRewards = totalRewards; i_deployedAt = block.timestamp; // i_token.transfer(address(this), i_totalRewards); @> for (uint256 i = 0; i < i_players.length; i++) { @> playersToRewards[i_players[i]] = i_rewards[i]; @> } } ``` - Another issue is that, if a `Pot` is created with a wrong `totalRewards` that for instance is less than the sum of the reward in the `rewards` array, then some players may never get to `claim` their rewards because the `Pot` will be underfunded by the `ContestManager::fundContest` function. ## PoC Here is a test for wrong `totalRewards` ```solidity function testSomePlayersCannotClaimCut() public mintAndApproveTokens { vm.startPrank(user); // manager creates pot with a wrong(smaller) totalRewards value- contest = ContestManager(conMan).createContest(players, rewards, IERC20(ERC20Mock(weth)), 6); ContestManager(conMan).fundContest(0); vm.stopPrank(); vm.startPrank(player1); Pot(contest).claimCut(); vm.stopPrank(); vm.startPrank(player2); // player 2 cannot claim cut because the pot is underfunded due to the wrong totalScore vm.expectRevert(); Pot(contest).claimCut(); vm.stopPrank(); } ``` ## Impact - Pot not created if large dynamic array of players and rewards is used - wrong totlRewards value leads to players inability to claim their cut ## Recommendations review the pot-creation design by, either using merkle tree to store the players and their rewards OR another solution is to use mapping to clearly map players to their reward and a special function to calculate the `totalRewards` each time a player is mapped to her reward. this `totalRewards` will be used later when claiming of rewards starts.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.