MyCut

First Flight #23
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

The owner can claim all contest rewards

Summary

The owner can claim all the contest rewards if there is no climants

https://github.com/Cyfrin/2024-08-MyCut/blob/946231db0fe717039429a11706717be568d03b54/src/Pot.sol#L49

Vulnerability Details

if there is no climants the owner can repetadly call pot::closeContest which allow him to receive ownerCut multiple times and drain the contest balance as mentioned in docs the owner take only 10% of the contest rewards

  • use the Following Poc in TestMyCut.t.sol

function testOwnerCanClaimAllContestPrizesIfThereIsNoClaimants() public mintAndApproveTokens {
vm.startPrank(user);
rewards = [500, 500];
totalRewards = 1000;
contest = ContestManager(conMan).createContest(
players,
rewards,
IERC20(ERC20Mock(weth)),
totalRewards
);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
assertEq(ERC20Mock(weth).balanceOf(contest), totalRewards);
assertEq(ERC20Mock(weth).balanceOf(address(conMan)), 0);
vm.warp(91 days);
// calling closeContest repetedally to drain pot
vm.startPrank(user);
while (ERC20Mock(weth).balanceOf(contest) > 0) {
ContestManager(conMan).closeContest(contest);
}
vm.stopPrank();
assertEq(ERC20Mock(weth).balanceOf(contest), 0);
assertEq(ERC20Mock(weth).balanceOf(address(conMan)), totalRewards);
}

Impact

  • Drain of pot balance

Tools Used

Manual Review + Foundry

Recommendations

  1. add a bool represent the contest status (closed or opened)

bool private isClosed;
  1. set the value of the flag to true at the end of pot::closeContest and add this condition to prevent calling the function repetadly

function closePot() external onlyOwner {
if (block.timestamp - i_deployedAt < 90 days) {
revert Pot__StillOpenForClaim();
}
+ if(isClosed){revert ();}
if (remainingRewards > 0) {
uint256 managerCut = remainingRewards / managerCutPercent;
i_token.transfer(msg.sender, managerCut);
uint256 claimantCut = (remainingRewards - managerCut) / i_players.length;
for (uint256 i = 0; i < claimants.length; i++) {
_transferReward(claimants[i], claimantCut);
}
}
+ isClosed = true;
}
Updates

Lead Judging Commences

equious Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect handling of zero claimant edge case

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.