MyCut

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

`players` and `rewards` arrays can have mismatched lengths — extra rewards silently ignored, tokens stuck

Root + Impact

Description

The Pot constructor doesn't check that players.length == rewards.length. If the rewards array is longer than the players array, the loop only maps rewards up to players.length and silently ignores the rest. The ignored rewards are counted toward totalRewards and funded, but no player can ever claim them.

// src/Pot.sol — constructor
for (uint256 i = 0; i < i_players.length; i++) {
playersToRewards[i_players[i]] = i_rewards[i];
}
// @> if rewards has more entries than players, extra entries are never mapped
// @> those tokens sit in the pot unclaimed forever

Risk

Likelihood: Requires the admin to make an input error. The admin is trusted, but there's no guard to catch this mistake.

Impact: Tokens corresponding to the unmapped rewards are permanently stuck. If players.length < rewards.length, the difference between totalRewards and the actually-claimable amount is locked.


Proof of Concept

2 players but 3 reward entries. The third 400-token reward has no corresponding player and can never be claimed.

function testL01_ArrayLengthMismatch() public {
address[] memory players = new address[](2);
players[0] = player1; players[1] = player2;
uint256[] memory rewards = new uint256[](3);
rewards[0] = 300e18; rewards[1] = 300e18; rewards[2] = 400e18;
vm.startPrank(owner);
address contest = conMan.createContest(players, rewards, IERC20(weth), 1000e18);
conMan.fundContest(0);
vm.stopPrank();
vm.prank(player1);
Pot(contest).claimCut();
vm.prank(player2);
Pot(contest).claimCut();
uint256 remaining = Pot(contest).getRemainingRewards();
assertEq(remaining, 400e18); // 400 tokens stuck
}

Recommended Mitigation

The constructor should verify that both arrays have the same length before proceeding with the reward mapping. Without this check, the loop silently skips any reward entries beyond players.length, leaving the corresponding tokens permanently locked. A simple require at the top of the constructor catches this at deployment time, before any funds are committed.

constructor(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards) {
+ require(players.length == rewards.length, "Array length mismatch");
i_players = players;
Updates

Lead Judging Commences

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