MyCut

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

Missing length validation between players and rewards leads to inconsistent reward mapping

Root + Impact

Description

  • The protocol creates a contest by assigning each player a reward during Pot deployment.

  • The issue is that no validation ensures players.length == rewards.length, causing mismatched indexing and inconsistent reward assignment.

// ContestManager.sol
function createContest(
address[] memory players,
uint256[] memory rewards,
IERC20 token,
uint256 totalRewards
)
public
onlyOwner
returns (address)
{
// @> No validation that players.length == rewards.length
Pot pot = new Pot(players, rewards, token, totalRewards);
contests.push(address(pot));
contestToTotalRewards[address(pot)] = totalRewards;
return address(pot);
}
// Pot.sol
constructor(
address[] memory players,
uint256[] memory rewards,
IERC20 token,
uint256 totalRewards
) {
i_players = players;
i_rewards = rewards;
// @> Assumes rewards[i] exists for every players[i]
for (uint256 i = 0; i < i_players.length; i++) {
playersToRewards[i_players[i]] = i_rewards[i];
}
}

Risk

Likelihood:

  • Contest configurations are manually provided during creation, making input mistakes realistic.

  • The contract accepts inconsistent array lengths without validation, allowing invalid states to be deployed.

Impact:

  • Some players may not receive rewards or may receive unintended values.

  • Reward distribution becomes inconsistent with the intended configuration, leading to incorrect or incomplete payouts.


Proof of Concept

A contest is created with fewer players than rewards:

  • players.length = 2

  • rewards.length = 3

During construction:

playersToRewards[user1] = 100 ether;
playersToRewards[user2] = 200 ether;

The extra reward (300 ether) is never assigned to any player, resulting in an inconsistent state where part of the rewards has no valid recipient.

function test_MismatchedLengths() public {
address[] memory players = new address[](2);
players[0] = user1;
players[1] = user2;
uint256[] memory rewards = new uint256[](3);
rewards[0] = 100 ether;
rewards[1] = 200 ether;
rewards[2] = 300 ether;
vm.startPrank(owner);
manager.createContest(players, rewards, token, 600 ether);
vm.stopPrank();
}

Recommended Mitigation

Validate input lengths before deploying the Pot.

function createContest(
address[] memory players,
uint256[] memory rewards,
IERC20 token,
uint256 totalRewards
)
public
onlyOwner
returns(address)
{
+ require(
+ players.length == rewards.length,
+ "Length mismatch"
+ );
Pot pot = new Pot(players, rewards, token, totalRewards);
contests.push(address(pot));
contestToTotalRewards[address(pot)] = totalRewards;
return address(pot);
}

This keeps the system invariant:

Each player ↔ exactly one reward
Updates

Lead Judging Commences

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