MyCut

AI First Flight #8
Beginner FriendlyFoundry
EXP
View results
Submission Details
Severity: low
Valid

Missing validation of `totalRewards` can prevent users from claiming rewards

Missing validation of totalRewards can prevent users from claiming rewards

Summary

The constructor accepts a totalRewards parameter but does not verify that it matches the sum of all individual player rewards.

If totalRewards is lower than the sum of rewards assigned to players, the contract may become underfunded, causing some users to be unable to successfully claim their rewards.

Vulnerability Details

In the constructor, totalRewards is directly assigned to i_totalRewards and remainingRewards:

i_totalRewards = totalRewards;
remainingRewards = totalRewards;

However, there is no validation ensuring that:

totalRewards == sum(rewards)

As a result, the contract can be initialized with an insufficient reward pool.

Proof Of Concept

  • Player A reward = 100

  • Player B reward = 100

  • Sum of rewards = 200

But the constructor is called with:

totalRewards = 150

In this scenario:

  • the first user may successfully claim;

  • subsequent claims can fail because the contract does not hold enough tokens to pay all rewards.

This breaks the protocol’s reward distribution guarantees and can lead to loss of funds for eligible users.

Impact

Eligible users may be unable to claim their rewards due to insufficient contract balance caused by incorrect initialization parameters.

This results in:

  • broken reward distribution logic;

  • denial of service for some users;

  • unfair reward allocation.

Recommended Mitigation

Instead of accepting totalRewards as an external parameter, compute it internally by summing all individual rewards during construction.

Example:

uint256 total;
for (uint256 i = 0; i < rewards.length; i++) {
total += rewards[i];
}
i_totalRewards = total;
remainingRewards = total;

Alternatively, add a validation ensuring that the provided totalRewards exactly matches the sum of all rewards.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 4 hours ago
Submission Judgement Published
Validated
Assigned finding tags:

[L-01] The logic for ContestManager::createContest is NOT efficient

## 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.

Support

FAQs

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

Give us feedback!