MyCut

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

ownerCut will be transfered to ContestFactory contract resulting that funds will be locked permanently

Summary

ContestManager::createContest deploy the pot contract hence the owner of the pot is the ContestManager contract which can't handle the ownerCut

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

Vulnerability Details

When ContestManager::createContest deploy the pot contract the owner of the pot is the ContestManager contract.so when the 90 days pass and there is unclaimed rewards and the owner call pot::closeContest to get the ownerCut the ownerCut transfered to the ContestManager instead of the owne of the contestManger.since the contestManager has no withdraw mechanism the ownerCut will be locked forever.

  • Use the following POC in TestMyCut.t.sol

    function testOwnerCutWillBeStuck() 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();
    //Tracking user Balance Before
    uint userBalanceBefore=ERC20Mock(weth).balanceOf(user);
    console.log("User Balance Before: ", userBalanceBefore);
    vm.startPrank(player1);
    Pot(contest).claimCut();
    vm.stopPrank();
    //Tracking claimant Balance Before
    uint256 claimantBalanceBefore = ERC20Mock(weth).balanceOf(player1);
    console.log("Claimant Balance Before: ", claimantBalanceBefore);//500 from his cut
    vm.warp(91 days);
    //check contestManager Balance before
    assertEq(ERC20Mock(weth).balanceOf(address(conMan)), 0);
    //closing contest
    vm.startPrank(user);
    ContestManager(conMan).closeContest(contest);
    vm.stopPrank();
    //Tracking user Balance After
    uint userBalanceAfter=ERC20Mock(weth).balanceOf(user);
    console.log("User Balance After: ", userBalanceAfter);
    //Tracking claimant Balance After
    uint256 claimantBalanceAfter = ERC20Mock(weth).balanceOf(player1);
    console.log("Claimant Balance After: ", claimantBalanceAfter);
    //Proving that there is no change in userBalance after calling closeContest
    assertEq(userBalanceBefore, userBalanceAfter);
    //Proving that the OwnerCut is transfered to the ContestManager contract (this will be stuck )
    assertEq(ERC20Mock(weth).balanceOf(address(conMan)), 50);// remainingRewards/percentage = 500/10=50
    // proving that contest owner is the ContestManager contract
    assertEq(Pot(contest).owner(), address(conMan));
    }

Impact

Losing of funds aka the ownerCut

Tools Used

Manual Review + Foundry

Recommendations

  • Use the following steps to implement this recommendation in pot::closeContest

  1. import contestManager in pot contract

import {ContestManager} from "./ContestManager.sol";
ContestManager private i_contestManager;
  1. Pass the contestManager contract address in the constructor

constructor(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards, address contestManager) {
i_contestManager = ContestManager(contestManager);
}
  1. add the contestManager address in contestManager::createContest

Pot pot = new Pot(players, rewards, token, totalRewards,address(this));
function closePot() external onlyOwner {
if (block.timestamp - i_deployedAt < 90 days) {
revert Pot__StillOpenForClaim();
}
if (remainingRewards > 0) {
uint256 managerCut = remainingRewards / managerCutPercent;
- i_token.transfer(msg.sender, managerCut);
+ i_token.transfer(i_contestManager.owner(), managerCut);
uint256 claimantCut = (remainingRewards - managerCut) / i_players.length;
for (uint256 i = 0; i < claimants.length; i++) {
_transferReward(claimants[i], claimantCut);
}
}
}
Updates

Lead Judging Commences

equious Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Owner's cut is stuck in ContestManager

Support

FAQs

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