MyCut

AI First Flight #8
Beginner FriendlyFoundry
EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

No validation that `totalRewards` matches the sum of individual rewards, causing token lockup or claim failures

Description

The Pot constructor accepts totalRewards and a rewards array as independent parameters with no check that they agree. fundContest() transfers totalRewards tokens into the Pot, but players claim based on the rewards array. A mismatch in either direction causes permanent fund loss.

Vulnerability Details

// src/Pot.sol, line 22-27
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; // @> set from parameter, not computed from rewards[]
// ...
}
// src/ContestManager.sol, line 28-38
function fundContest(uint256 index) public onlyOwner {
// ...
uint256 totalRewards = contestToTotalRewards[address(pot)]; // @> uses stored totalRewards
token.transferFrom(msg.sender, address(pot), totalRewards); // @> transfers this amount
}

Two failure modes:

  1. totalRewards > sum(rewards): The Pot receives more tokens than players can claim. After all players claim and closePot() runs, excess tokens remain locked in the Pot with no recovery function.

  2. totalRewards < sum(rewards): Early claimants succeed, but later claimants' transfer() calls fail when the Pot's token balance runs out. Those players permanently lose their rewards (their mapping entries are zeroed before the failed transfer).

Risk

Likelihood:

  • Requires the admin to pass mismatched values. The admin is trusted, so this is an accidental misconfiguration rather than an attack. But there is no safety net against a simple arithmetic mistake.

Impact:

  • In the over-funded case, excess tokens are permanently locked. In the under-funded case, some players lose their rewards entirely. Both outcomes result in unrecoverable fund loss.

PoC

No PoC provided. The vulnerability is a missing validation check in the constructor, exercisable only by the trusted admin providing mismatched parameters.

Recommendations

Compute totalRewards from the rewards array in the constructor instead of accepting it as a separate parameter. This eliminates the mismatch entirely.

- constructor(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards) {
+ constructor(address[] memory players, uint256[] memory rewards, IERC20 token) {
+ uint256 totalRewards;
+ for (uint256 i = 0; i < rewards.length; i++) {
+ totalRewards += rewards[i];
+ }
i_totalRewards = totalRewards;
remainingRewards = totalRewards;
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 13 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!