MyCut

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

Low-severity issues: unchecked ERC20 transfers, missing validations, no rescue path, fund-lifecycle and whole-distribution DoS gaps

A batch of low-severity robustness issues in Pot.sol / ContestManager.sol — unchecked ERC20 transfers, missing input validation, no rescue path, and a whole-distribution DoS.

Description

Several lower-severity issues. Each is individually best-practice / robustness / edge-case, but several compound the High and Medium findings reported separately.

  1. Unchecked ERC20 return values — Pot.sol (i_token.transfer in claimCut / closePot / _transferReward) and ContestManager.fundContest (transferFrom) ignore the bool return. A token that returns false instead of reverting would mis-account (credit/claim without moving funds). Use SafeERC20.

  2. No players.length == rewards.length check in the Pot constructor — a mismatch either reverts at deploy (DoS) or silently truncates the reward set.

  3. No rescue/withdraw path anywhere — combined with the rounding/denominator issues, any residual balance (especially the ~90% stranded when nobody claims) is permanently unrecoverable.

  4. fundContest has no double-funding guard — the owner can fund the same contest repeatedly, over-transferring tokens with no accounting of what was already sent.

  5. Pot is never funded at construction (the i_token.transfer is commented out); nothing on-chain ties funding to the lifecycle, so an unfunded Pot makes claimCut/closePot revert on transfer.

  6. Whole-distribution DoS — closePot's loop reverts entirely if any one claimant cannot receive the token (e.g. a blocklist token), blocking the payout for everyone.

  7. Dead reward <= 0 check on a uint256 (true only when reward == 0); the constructor also has no zero-address or duplicate-player guard, and duplicate players inflate i_players.length, worsening the denominator bug.

Risk

Likelihood:

Most require a specific trigger — a non-reverting or blocklist token, an owner input mistake (mismatched arrays, double funding), or a zero/duplicate address — rather than an arbitrary attacker, so each is individually low likelihood.

Impact:

Individually low (best-practice / robustness / edge-case griefing), but several compound the High/Medium findings: the unchecked transfers, the absent rescue path, and duplicate players all amplify the fund-loss issues reported separately.

Proof of Concept

Illustrative snippets from the in-scope code — these are unchecked / dead-code paths, no exploit transaction required:

// (1) unchecked return — a non-reverting token can mis-account
i_token.transfer(to, amount); // bool return ignored
i_token.transferFrom(msg.sender, addr, amount); // fundContest, ignored
// (7) dead check on an unsigned value (can never be < 0)
require(reward <= 0, ...); // only ever true when reward == 0

Recommended Mitigation

Use SafeERC20 for all token moves; validate players.length == rewards.length, reject zero addresses and duplicate players; add a rescue/sweep; guard fundContest against re-funding; fund the Pot as part of creation; and prefer pull-payments (or skip-on-failure) in the distribution loop.

Updates

Lead Judging Commences

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