MyCut

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

Admin may fund the contest a second time

Summary

The admin can fund the contest a second time, which will increase the contract's token balance, but it won't increase the rewards available to users.

Vulnerability Details

The ContestManager::fundContest function allows admin to fund the contest rewards. When the admin calls the function more than once, the contract's token balance will increase, but will not increase the amount of remaining rewards to be distributed to users, which is stored in the Pot::remainingRewards variable. The pool of rewards for users, including any unclaimed amounts, will remain at the initial amount specified when the contest was created.

Impact

Excess funds added to the contract will be locked at the contest's contract address and cannot be withdrawn.

Proof of Concept

When the admin calls the ContestManager::fundContest function a second time, the contract's token balance increases, but the amount of rewards available to users remains unchanged.

Proof of Code

Add the following code to the TestMyCut.t.sol file within the TestMyCut contract.

function testFundContestSecondTime() public mintAndApproveTokens {
rewards = [500, 500];
totalRewards = 1000;
vm.startPrank(user);
contest = ContestManager(conMan).createContest(players, rewards, IERC20(ERC20Mock(weth)), totalRewards);
ContestManager(conMan).fundContest(0);
uint256 initialContestTokenBalance = ERC20Mock(weth).balanceOf(contest);
uint256 initialRemainingRewards = Pot(contest).getRemainingRewards();
// admin funds the contest for second time
ContestManager(conMan).fundContest(0);
uint256 updatedContestTokenBalance = ERC20Mock(weth).balanceOf(contest);
uint256 updatedRemainingRewards = Pot(contest).getRemainingRewards();
// contest contract token balance doubled after second funding
assertEq(initialContestTokenBalance * 2, updatedContestTokenBalance);
// remaining rewards are the same after second funding
assertEq(initialRemainingRewards, updatedRemainingRewards);
assertLt(updatedRemainingRewards, updatedContestTokenBalance);
}

Tools Used

  • Manual Review

  • Foundry

Recommended mitigation

One possible solution is to provide a mechanism for blocking the funding of a Pot which was already funded. A bool flag could be set after a contest is funded and prevent it from being funded again.

Changes to provide in Pot.sol file inside the Pot contract:

+ bool private isFunded;
+ function setFunded() external onlyOwner {
+ isFunded = true;
+ }
+
+ function checkIsFunded() public view returns (bool) {
+ return isFunded;
+ }

Changes to provide in ContestManager.sol file inside the ContestManager contract:

+ error ContestManager__ContestAlreadyFunded();
function fundContest(uint256 index) public onlyOwner {
Pot pot = Pot(contests[index]);
IERC20 token = pot.getToken();
uint256 totalRewards = contestToTotalRewards[address(pot)];
if (token.balanceOf(msg.sender) < totalRewards) {
revert ContestManager__InsufficientFunds();
}
+ if (pot.checkIsFunded()) {
+ revert ContestManager__ContestAlreadyFunded();
+ }
+
+ pot.setFunded();
token.transferFrom(msg.sender, address(pot), totalRewards);
}
Updates

Lead Judging Commences

equious Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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