MyCut

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

Unchecked return value of token.transferFrom() in fundContest allows a pot to appear funded when it holds no tokens

Root + Impact

Unchecked return value of token.transferFrom() in fundContest allows a pot to appear funded when it holds no tokens

Description

  • Description: fundContest calls token.transferFrom() without checking its return value.

  • If the transfer silently fails, the Pot contract holds no tokens but contestToTotalRewards still reflects the full amount. All subsequent claimCut() calls will fail or draw from incorrect balances.

// Root cause in the codebase with @> marks to highlight the relevant section
function fundContest(uint256 index) public onlyOwner { //audit-gas should be external
Pot pot = Pot(contests[index]);
IERC20 token = pot.getToken();
uint256 totalRewards = contestToTotalRewards[address(pot)];
if (token.balanceOf(msg.sender) < totalRewards) {
revert ContestManager__InsufficientFunds();
}
@> token.transferFrom(msg.sender, address(pot), totalRewards); //audit- medium we are not checking the transaction return false or true, lead to fake pot contract variables value
}

Risk

Likelihood:

  • Occurs whenever a non-standard ERC20 token that returns false instead of reverting is used

  • The protocol accepts any IERC20 token with no whitelist or validation

Impact:

  • The pot is marked as funded but holds no tokens

  • All player claim attempts will fail, effectively bricking the entire contest

Proof of Concept

function testFundContestSilentFailure() public {
MockReturnFalseERC20 token = new MockReturnFalseERC20();
token.mint(owner, 1000e18);
vm.startPrank(owner);
token.approve(address(contestManager), 1000e18);
address[] memory players = new address[](1);
players[0] = alice;
uint256[] memory rewards = new uint256[](1);
rewards[0] = 1000e18;
address potAddress = contestManager.createContest(players, rewards, token, 1000e18);
contestManager.fundContest(0);
vm.stopPrank();
assertEq(contestManager.getContestTotalRewards(potAddress), 1000e18);
assertEq(token.balanceOf(potAddress), 0);
vm.prank(alice);
vm.expectRevert();
Pot(potAddress).claimCut();
}

Recommended Mitigation

- remove this code
+using SafeERC20 for IERC20;
-token.transferFrom(msg.sender, address(pot), totalRewards);
+token.safeTransferFrom(msg.sender, address(pot), totalRewards);
+ add this code
Updates

Lead Judging Commences

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