MyCut

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

`totalRewards` Not Validated Against Sum of `rewards[]` Array → Pot Can Be Funded with Mismatched Amounts

Description

  • Normal: createContest() accepts rewards[] (individual allocations) and totalRewards (total pool). These must match for correct accounting.

  • Bug: No validation ensures sum(rewards) == totalRewards. fundContest() transfers totalRewards unconditionally, regardless of what rewards[] actually sums to.

// src/ContestManager.sol:20-24
function createContest(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards)
public onlyOwner returns (address)
{
//@> No check: sum(rewards) == totalRewards
Pot pot = new Pot(players, rewards, token, totalRewards);
contests.push(address(pot));
return address(pot);
}

Risk

Likelihood:

  • Human error when entering totalRewards manually — off-by-one or typo produces mismatch

  • No compiler or runtime check catches the discrepancy

Impact:

  • totalRewards > sum(rewards): Pot holds more tokens than players can claim — excess permanently unaccounted

  • totalRewards < sum(rewards): Not enough tokens — last claimants get nothing, silent failure

  • Both cases break the protocol's accounting with no revert or error

Proof of Concept

function test_MismatchedTotalRewards() public {
uint256 actualSum = 500e18;
uint256 declaredTotal = 1000e18; // 2x the actual sum
uint256[] memory rewards = new uint256[](2);
rewards[0] = 250e18; rewards[1] = 250e18;
address[] memory players = new address[](2);
players[0] = player1; players[1] = player2;
vm.prank(owner);
address potAddr = manager.createContest(players, rewards, IERC20(address(token)), declaredTotal);
token.transfer(owner, declaredTotal);
vm.startPrank(owner);
token.approve(address(manager), declaredTotal);
manager.fundContest(0);
vm.stopPrank();
// Pot received 1000 tokens but players only have claims for 500
assertEq(token.balanceOf(potAddr), declaredTotal);
// 500 tokens have no claimant
}

Run with:

forge test --match-test test_MismatchedTotalRewards -vvv

Result: [PASS] — Pot funded with 2x the allocated rewards.

Recommended Mitigation

function createContest(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards)
public onlyOwner returns (address)
{
+ uint256 sum;
+ for (uint256 i = 0; i < rewards.length; i++) sum += rewards[i];
+ require(sum == totalRewards, "Total rewards mismatch");
Pot pot = new Pot(players, rewards, token, totalRewards);
// ...
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 5 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!