MyCut

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

Unchecked ERC20 return values allow silent funding and reward loss

Description

ContestManager.fundContest() and Pot._transferReward() use raw ERC20 transferFrom/transfer and ignore returned bool.

When token returns false (without revert), state still advances:

  • contest appears funded when it is not

  • claim accounting is reduced even when payout did not happen

Affected lines:

  • src/ContestManager.soltoken.transferFrom(msg.sender, address(pot), totalRewards);

  • src/Pot.soli_token.transfer(player, reward);

Risk

Likelihood: Medium

  • Protocol accepts generic IERC20 behavior.

  • False-return tokens exist in production and integrations.

Impact: High

  • Silent underfunding of pots.

  • playersToRewards[player] can be zeroed while claimant receives no tokens.

  • Accounting drift and effective reward loss.

Proof of Concept

Created deterministic tests using a false-returning mock token.

Files:

  • test/FalseReturnERC20Mock.sol

  • test/MyCutSecondPassFindings.t.sol

Repro 1 (funding fails silently):

  1. Create contest with totalRewards = 100.

  2. Call fundContest(0).

  3. transferFrom returns false, no revert.

  4. Assert balanceOf(pot) == 0.

Repro 2 (claim burns accounting without payout):

  1. Setup contest where player1 reward is 60.

  2. Call player1.claimCut().

  3. transfer returns false, no revert.

  4. Assert:

  • checkCut(player1): 60 -> 0

  • remainingRewards decreased by 60

  • player1 token balance unchanged.

Validation command:

forge test --match-contract MyCutSecondPassFindingsTest -vvv

Recommended Mitigation

Use OpenZeppelin SafeERC20 everywhere transfers occur and enforce transfer success by revert semantics.

- token.transferFrom(msg.sender, address(pot), totalRewards);
+ token.safeTransferFrom(msg.sender, address(pot), totalRewards);
- i_token.transfer(player, reward);
+ i_token.safeTransfer(player, reward);

Add post-condition checks on critical paths (funding / claim / close)
Ensure expected token delta on recipient matches accounted reward change

Updates

Lead Judging Commences

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