MyCut

AI First Flight #8
Beginner FriendlyFoundry
EXP
View results
Submission Details
Severity: high
Valid

Permanent Fund Lockup Due to Wrong Divisor in closePot() Distribution

# Permanent Fund Lockup Due to Wrong Divisor in closePot() Distribution
## Summary
The incorrect divisor in `Pot.sol:57` will cause permanent loss of 63-100% of remaining funds for claimants as the `closePot()` function distributes bonus rewards by dividing by `i_players.length` (total players) but only iterates over `claimants.length` (actual claimants), leaving the majority of tokens locked forever in the Pot contract.
## Root Cause
In `Pot.sol:57` the claimant bonus distribution uses the wrong denominator:
```solidity
uint256 claimantCut = (remainingRewards - managerCut) / i_players.length; // ✗ BUG: Should be claimants.length
for (uint256 i = 0; i < claimants.length; i++) {
_transferReward(claimants[i], claimantCut);
}
```
The code divides by `i_players.length` (total number of registered players) but only distributes to `claimants.length` recipients. This mathematical error causes:
1. Each claimant receives a fraction of their fair share
2. The difference is permanently locked in the Pot contract with no recovery mechanism
**Additional Bug:** The manager cut in `Pot.sol:55` is sent to `msg.sender` which is the `ContestManager` contract (not the admin), and `ContestManager` has no withdrawal function, causing those funds to also be stuck.
## Internal Pre-conditions
1. At least one player needs to NOT claim their reward before the 90-day period expires
2. This is expected behavior - the protocol explicitly allows 90 days for claims
## External Pre-conditions
None - this is a pure protocol logic bug requiring no external conditions.
## Attack Path
This is not an active attack but a vulnerability path that occurs during normal protocol operation:
1. Admin creates a contest with 10 players, each entitled to 100 tokens (1000 total)
2. Some players claim their rewards (e.g., only player1 claims 100 tokens)
3. After 90 days, admin calls `ContestManager.closeContest()` to distribute remaining funds
4. Buggy calculation: `claimantCut = (900 - 90) / 10 = 81` per claimant
5. But only 1 claimant exists, so only `1 * 81 = 81` tokens are distributed
6. Result: `900 - 90 (manager) - 81 (claimant bonus) = 729 tokens` locked forever
## Impact
The claimants suffer permanent loss of 63-100% of remaining rewards depending on the claim ratio:
| Scenario | Players | Claimants | Remaining | Locked Forever | Loss % |
|----------|---------|-----------|-----------|----------------|--------|
| Worst Case | 10 | 0 | 1000 | 900 (+ 100 in ContestManager) | **100%** |
| Typical | 10 | 1 | 900 | 729 | **81%** |
| Moderate | 10 | 3 | 700 | 441 | **63%** |
**Quantified Impact:**
- For a 1000 ETH prize pool with 10 players where only 1 claims:
- Expected claimant bonus: 810 ETH
- Actual claimant bonus: 81 ETH
- **Permanent loss: 729 ETH (72.9% of remaining funds)**
## PoC
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test, console} from "forge-std/Test.sol";
import {ContestManager} from "../../src/ContestManager.sol";
import {Pot} from "../../src/Pot.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
/**
* @title ERC20Mock - Simple mock ERC20 for testing
*/
contract ERC20Mock is IERC20 {
string public name;
string public symbol;
uint8 public decimals = 18;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
}
function mint(address to, uint256 amount) external {
balanceOf[to] += amount;
totalSupply += amount;
}
function transfer(address to, uint256 amount) external returns (bool) {
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
allowance[from][msg.sender] -= amount;
balanceOf[from] -= amount;
balanceOf[to] += amount;
emit Transfer(from, to, amount);
return true;
}
}
/**
* @title ClaimantCutWrongDivisorPoC
* @notice PoC demonstrating that closePot() uses wrong divisor causing permanent fund lockup
*
* ## Vulnerability Summary
* In Pot.sol:closePot(), the claimant bonus distribution uses i_players.length as divisor
* but only iterates over claimants.length recipients. This causes:
* 1. Each claimant receives LESS than their fair share
* 2. Remaining tokens are PERMANENTLY LOCKED in the Pot contract
*
* ## Attack Scenario
* - 10 players, 1000 tokens total distributed equally (100 each)
* - Only 1 player claims their 100 tokens
* - After 90 days, closePot() is called with 900 remaining
* - Manager gets: 900 / 10 = 90 tokens (10%)
* - Claimant bonus: (900 - 90) / 10 = 81 tokens per claimant
* - But only 1 claimant exists! They get: 1 * 81 = 81 tokens
* - Locked forever: 900 - 90 - 81 = 729 tokens (72.9% of remaining!)
*/
contract ClaimantCutWrongDivisorPoC is Test {
ContestManager public contestManager;
ERC20Mock public token;
address public admin = makeAddr("admin");
// 10 players for clear demonstration
address public player1 = makeAddr("player1");
address public player2 = makeAddr("player2");
address public player3 = makeAddr("player3");
address public player4 = makeAddr("player4");
address public player5 = makeAddr("player5");
address public player6 = makeAddr("player6");
address public player7 = makeAddr("player7");
address public player8 = makeAddr("player8");
address public player9 = makeAddr("player9");
address public player10 = makeAddr("player10");
address[] public players;
uint256[] public rewards;
uint256 public constant TOTAL_REWARDS = 1000 ether;
function setUp() public {
// Setup players array
players = new address[](10);
players[0] = player1;
players[1] = player2;
players[2] = player3;
players[3] = player4;
players[4] = player5;
players[5] = player6;
players[6] = player7;
players[7] = player8;
players[8] = player9;
players[9] = player10;
// Each player gets 100 ether (fair distribution)
rewards = new uint256[](10);
for (uint i = 0; i < 10; i++) {
rewards[i] = 100 ether;
}
// Deploy contracts
vm.startPrank(admin);
contestManager = new ContestManager();
token = new ERC20Mock("Test Token", "TEST");
token.mint(admin, TOTAL_REWARDS);
token.approve(address(contestManager), TOTAL_REWARDS);
vm.stopPrank();
}
/**
* @notice Test demonstrating the vulnerability with quantified fund lockup
*/
function test_PermanentFundLockup_WrongDivisor() public {
console.log("=== ClaimantCut Wrong Divisor Vulnerability PoC ===");
console.log("");
// Step 1: Admin creates and funds the contest
vm.startPrank(admin);
address potAddress = contestManager.createContest(
players,
rewards,
IERC20(address(token)),
TOTAL_REWARDS
);
contestManager.fundContest(0);
vm.stopPrank();
Pot pot = Pot(potAddress);
console.log("[SETUP] Contest Created and Funded");
console.log(" Total Players: 10");
console.log(" Total Rewards: %s tokens", TOTAL_REWARDS / 1e18);
console.log(" Pot Balance: %s tokens", token.balanceOf(potAddress) / 1e18);
console.log("");
// Step 2: Only player1 claims their reward (simulating partial claims)
vm.prank(player1);
pot.claimCut();
uint256 player1Balance = token.balanceOf(player1);
console.log("[CLAIM] Player1 claims their cut");
console.log(" Player1 received: %s tokens", player1Balance / 1e18);
console.log(" Remaining in Pot: %s tokens", pot.getRemainingRewards() / 1e18);
console.log("");
// Step 3: Fast forward 91 days
vm.warp(block.timestamp + 91 days);
console.log("[TIME] 91 days passed, pot ready to close");
console.log("");
// Step 4: Record balances before close
uint256 adminBalBefore = token.balanceOf(admin);
uint256 player1BalBefore = token.balanceOf(player1);
uint256 potBalBefore = token.balanceOf(potAddress);
uint256 remainingBefore = pot.getRemainingRewards();
console.log("[BEFORE CLOSE]");
console.log(" Admin balance: %s tokens", adminBalBefore / 1e18);
console.log(" Player1 balance: %s tokens", player1BalBefore / 1e18);
console.log(" Pot balance: %s tokens", potBalBefore / 1e18);
console.log(" Remaining rewards: %s tokens", remainingBefore / 1e18);
console.log("");
// Step 5: Close the pot - THIS IS WHERE THE BUG MANIFESTS
vm.prank(admin);
contestManager.closeContest(potAddress);
// Step 6: Analyze the damage
uint256 adminBalAfter = token.balanceOf(admin);
uint256 player1BalAfter = token.balanceOf(player1);
uint256 potBalAfter = token.balanceOf(potAddress);
uint256 managerReceived = adminBalAfter - adminBalBefore;
uint256 player1Bonus = player1BalAfter - player1BalBefore;
uint256 lockedForever = potBalAfter;
console.log("[AFTER CLOSE - BUG DEMONSTRATED]");
console.log(" Manager received (10%): %s tokens", managerReceived / 1e18);
console.log(" Player1 bonus: %s tokens", player1Bonus / 1e18);
console.log(" ");
console.log(" >>> TOKENS LOCKED FOREVER IN POT: %s tokens <<<", lockedForever / 1e18);
console.log("");
// Step 7: Calculate what SHOULD have happened
// Expected: claimantCut = (remaining - managerCut) / claimants.length = (900 - 90) / 1 = 810
// Actual: claimantCut = (remaining - managerCut) / i_players.length = (900 - 90) / 10 = 81
// Locked: 810 - 81 = 729 tokens
uint256 expectedClaimantBonus = (remainingBefore - managerReceived); // 810 ether
uint256 actualClaimantBonus = player1Bonus; // 81 ether
uint256 stolenFromClaimant = expectedClaimantBonus - actualClaimantBonus;
console.log("[IMPACT ANALYSIS]");
console.log(" Expected claimant bonus: %s tokens", expectedClaimantBonus / 1e18);
console.log(" Actual claimant bonus: %s tokens", actualClaimantBonus / 1e18);
console.log(" Claimant LOSS: %s tokens", stolenFromClaimant / 1e18);
console.log("");
console.log(" Loss percentage: %s%%", (lockedForever * 100) / TOTAL_REWARDS);
console.log("");
// Assertions proving the vulnerability
assertGt(lockedForever, 0, "Tokens should be locked in pot");
assertEq(lockedForever, 729 ether, "Exactly 729 tokens should be locked");
assertEq(player1Bonus, 81 ether, "Claimant only received 81 tokens instead of 810");
console.log("=== PoC SUCCESSFUL: %s tokens (72.9%%) permanently locked ===", lockedForever / 1e18);
}
/**
* @notice Worst case: No one claims, ALL tokens locked forever
* @dev ADDITIONAL BUG DISCOVERED: Manager cut goes to ContestManager contract, NOT the admin!
*/
function test_WorstCase_NoOneClaims_AllTokensLocked() public {
console.log("=== WORST CASE: No Claims = Total Fund Lockup ===");
console.log("");
vm.startPrank(admin);
address potAddress = contestManager.createContest(
players,
rewards,
IERC20(address(token)),
TOTAL_REWARDS
);
contestManager.fundContest(0);
vm.stopPrank();
Pot pot = Pot(potAddress);
console.log("[SETUP] Contest Created, NO ONE CLAIMS");
console.log(" Total Rewards: %s tokens", TOTAL_REWARDS / 1e18);
console.log("");
// Fast forward and close
vm.warp(block.timestamp + 91 days);
uint256 adminBalBefore = token.balanceOf(admin);
uint256 contestManagerBalBefore = token.balanceOf(address(contestManager));
vm.prank(admin);
contestManager.closeContest(potAddress);
uint256 adminBalAfter = token.balanceOf(admin);
uint256 contestManagerBalAfter = token.balanceOf(address(contestManager));
uint256 managerReceivedByAdmin = adminBalAfter - adminBalBefore;
uint256 managerReceivedByContract = contestManagerBalAfter - contestManagerBalBefore;
uint256 lockedInPot = token.balanceOf(potAddress);
console.log("[RESULT - MULTIPLE BUGS REVEALED]");
console.log(" Admin received: %s tokens (SHOULD be 100)", managerReceivedByAdmin / 1e18);
console.log(" ContestManager contract received: %s tokens (BUG #2!)", managerReceivedByContract / 1e18);
console.log(" >>> LOCKED IN POT FOREVER: %s tokens <<<", lockedInPot / 1e18);
console.log("");
// BUG #1: Claimant loop runs 0 times, so 90% stays in pot
// BUG #2: Manager cut of 10% goes to ContestManager contract, NOT admin
// ContestManager has no withdraw function = funds stuck there too!
console.log("[BUG #1] Wrong divisor: 90%% locked in Pot contract");
console.log("[BUG #2] Manager cut goes to ContestManager (no withdraw!) = stuck");
console.log("");
console.log("Total unrecoverable: %s tokens (100%%!)", (lockedInPot + managerReceivedByContract) / 1e18);
// Verify the bugs
assertEq(managerReceivedByAdmin, 0, "Admin gets NOTHING - bug #2");
assertEq(managerReceivedByContract, 100 ether, "ContestManager gets the 10% cut");
assertEq(lockedInPot, 900 ether, "90% locked in Pot - bug #1");
console.log("");
console.log("=== CRITICAL: 100%% of protocol funds UNRECOVERABLE ===");
}
/**
* @notice Demonstrate the difference between actual vs expected distribution
*/
function test_CompareActualVsExpectedDistribution() public {
console.log("=== Actual vs Expected Distribution Analysis ===");
console.log("");
vm.startPrank(admin);
address potAddress = contestManager.createContest(
players,
rewards,
IERC20(address(token)),
TOTAL_REWARDS
);
contestManager.fundContest(0);
vm.stopPrank();
Pot pot = Pot(potAddress);
// 3 out of 10 players claim
vm.prank(player1);
pot.claimCut();
vm.prank(player2);
pot.claimCut();
vm.prank(player3);
pot.claimCut();
uint256 remaining = pot.getRemainingRewards(); // 700 ether
console.log("[SCENARIO] 3 out of 10 players claimed");
console.log(" Players claimed: 300 tokens");
console.log(" Remaining: %s tokens", remaining / 1e18);
console.log("");
vm.warp(block.timestamp + 91 days);
uint256 p1Before = token.balanceOf(player1);
uint256 p2Before = token.balanceOf(player2);
uint256 p3Before = token.balanceOf(player3);
vm.prank(admin);
contestManager.closeContest(potAddress);
uint256 p1Bonus = token.balanceOf(player1) - p1Before;
uint256 p2Bonus = token.balanceOf(player2) - p2Before;
uint256 p3Bonus = token.balanceOf(player3) - p3Before;
uint256 locked = token.balanceOf(potAddress);
// Buggy calculation:
// managerCut = 700 / 10 = 70
// claimantCut = (700 - 70) / 10 = 63 per claimant
// Total distributed to claimants = 3 * 63 = 189
// Locked = 700 - 70 - 189 = 441
// CORRECT calculation should be:
// managerCut = 700 / 10 = 70
// claimantCut = (700 - 70) / 3 = 210 per claimant
// Total distributed = 3 * 210 = 630
// Locked = 0
console.log("[ACTUAL DISTRIBUTION (BUGGY)]");
console.log(" Each claimant bonus: %s tokens", p1Bonus / 1e18);
console.log(" Total to claimants: %s tokens", (p1Bonus + p2Bonus + p3Bonus) / 1e18);
console.log(" Locked: %s tokens", locked / 1e18);
console.log("");
uint256 expectedPerClaimant = (remaining - (remaining / 10)) / 3; // 210 ether
console.log("[EXPECTED DISTRIBUTION (CORRECT)]");
console.log(" Each claimant should get: %s tokens", expectedPerClaimant / 1e18);
console.log(" Locked should be: 0 tokens");
console.log("");
console.log("[LOSS]");
console.log(" Each claimant loses: %s tokens", (expectedPerClaimant - p1Bonus) / 1e18);
console.log(" Total locked forever: %s tokens (%s%%)", locked / 1e18, (locked * 100) / remaining);
assertEq(p1Bonus, 63 ether, "Bug: claimant gets 63 instead of 210");
assertEq(locked, 441 ether, "63% of remaining funds locked");
}
}
```
### Files Included
- `ClaimantCutWrongDivisorPoC.t.sol` - Main PoC test file
### Environment Setup
1. Install dependencies:
```bash
forge install foundry-rs/forge-std OpenZeppelin/openzeppelin-contracts
```
2. Modify `foundry.toml` to include PoC test path:
```toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
test = "poc"
```
### Run Command
```bash
forge test --match-contract ClaimantCutWrongDivisorPoC -vvv
```
### Expected Output
```
[PASS] test_CompareActualVsExpectedDistribution() (gas: 1732754)
Logs:
=== Actual vs Expected Distribution Analysis ===
[SCENARIO] 3 out of 10 players claimed
Players claimed: 300 tokens
Remaining: 700 tokens
[ACTUAL DISTRIBUTION (BUGGY)]
Each claimant bonus: 63 tokens
Total to claimants: 189 tokens
Locked: 441 tokens
[EXPECTED DISTRIBUTION (CORRECT)]
Each claimant should get: 210 tokens
Locked should be: 0 tokens
[LOSS]
Each claimant loses: 147 tokens
Total locked forever: 441 tokens (63%)
[PASS] test_PermanentFundLockup_WrongDivisor() (gas: 1672704)
Logs:
=== ClaimantCut Wrong Divisor Vulnerability PoC ===
[SETUP] Contest Created and Funded
Total Players: 10
Total Rewards: 1000 tokens
Pot Balance: 1000 tokens
[CLAIM] Player1 claims their cut
Player1 received: 100 tokens
Remaining in Pot: 900 tokens
[TIME] 91 days passed, pot ready to close
[AFTER CLOSE - BUG DEMONSTRATED]
Manager received (10%): 0 tokens
Player1 bonus: 81 tokens
>>> TOKENS LOCKED FOREVER IN POT: 729 tokens <<<
[IMPACT ANALYSIS]
Expected claimant bonus: 900 tokens
Actual claimant bonus: 81 tokens
Claimant LOSS: 819 tokens
Loss percentage: 72%
=== PoC SUCCESSFUL: 729 tokens (72.9%) permanently locked ===
[PASS] test_WorstCase_NoOneClaims_AllTokensLocked() (gas: 1589723)
Logs:
=== WORST CASE: No Claims = Total Fund Lockup ===
[SETUP] Contest Created, NO ONE CLAIMS
Total Rewards: 1000 tokens
[RESULT - MULTIPLE BUGS REVEALED]
Admin received: 0 tokens (SHOULD be 100)
ContestManager contract received: 100 tokens (BUG #2!)
>>> LOCKED IN POT FOREVER: 900 tokens <<<
[BUG #1] Wrong divisor: 90% locked in Pot contract
[BUG #2] Manager cut goes to ContestManager (no withdraw!) = stuck
Total unrecoverable: 1000 tokens (100%!)
=== CRITICAL: 100% of protocol funds UNRECOVERABLE ===
Suite result: ok. 3 passed; 0 failed; 0 skipped
```
## Mitigation
Replace `i_players.length` with `claimants.length` in the divisor:
```diff
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(owner(), managerCut); // Fix: Send to owner, not msg.sender
- uint256 claimantCut = (remainingRewards - managerCut) / i_players.length;
+ uint256 claimantCut = claimants.length > 0
+ ? (remainingRewards - managerCut) / claimants.length
+ : 0;
for (uint256 i = 0; i < claimants.length; i++) {
_transferReward(claimants[i], claimantCut);
}
+
+ // Transfer any remaining dust to owner
+ uint256 remaining = i_token.balanceOf(address(this));
+ if (remaining > 0) {
+ i_token.transfer(owner(), remaining);
+ }
}
}
```
**Key fixes:**
1. Divide by `claimants.length` instead of `i_players.length`
2. Add zero-check to prevent division by zero when no one claims
3. Send manager cut to `owner()` instead of `msg.sender`
4. Add sweep mechanism to recover any rounding dust
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 2 days ago
Submission Judgement Published
Validated
Assigned finding tags:

[H-02] Incorrect logic in `Pot::closePot` leads to unfair distribution to `claimants`, potentially locking the funds with no way to take that out

## Description in `closePot` function while calclulating the shares for claimaint cut, `i_players.length` is used, instead of `claimants.length`, causing low amount being distributed to claimants. ## Vulnerability Details [2024-08-MyCut/src/Pot.sol at main · Cyfrin/2024-08-MyCut (github.com)](https://github.com/Cyfrin/2024-08-MyCut/blob/main/src/Pot.sol#L57) `Pot::closePot` function is meant to be called once contest passed 90 days, it sends the owner cut to owner and rest is splitted among the users who claimed b/w 90 days period. However, current implementation is wrong.&#x20; It uses total users (i_players.length) instead of the users (claimants.length) who claimed during the duration. This creates an unfair distribution to the participants and some of the funds could be locked in the contract. In worst case scenerio, it could be 90% if nobody has claimed from the protocol during the 90 days duration. ## POC In existing test suite, add following test: ```solidity function testUnfairDistributionInClosePot() public mintAndApproveTokens { // Setup address[] memory testPlayers = new address[](3); testPlayers[0] = makeAddr("player1"); testPlayers[1] = makeAddr("player2"); testPlayers[2] = makeAddr("player3"); uint256[] memory testRewards = new uint256[](3); testRewards[0] = 400; testRewards[1] = 300; testRewards[2] = 300; uint256 testTotalRewards = 1000; // Create and fund the contest vm.startPrank(user); address testContest = ContestManager(conMan).createContest( testPlayers, testRewards, IERC20(ERC20Mock(weth)), testTotalRewards ); ContestManager(conMan).fundContest(0); vm.stopPrank(); // Only player1 claims their reward vm.prank(testPlayers[0]); Pot(testContest).claimCut(); // Fast forward 91 days vm.warp(block.timestamp + 91 days); // Record balances before closing the pot uint256 player1BalanceBefore = ERC20Mock(weth).balanceOf( testPlayers[0] ); // Close the contest vm.prank(user); ContestManager(conMan).closeContest(testContest); // Check balances after closing the pot uint256 player1BalanceAfter = ERC20Mock(weth).balanceOf(testPlayers[0]); // Calculate expected distributions uint256 remainingRewards = 600; // 300 + 300 unclaimed rewards uint256 ownerCut = remainingRewards / 10; // 10% of remaining rewards uint256 distributionPerPlayer = (remainingRewards - ownerCut) / 1; // as only 1 user claimed uint256 fundStucked = ERC20Mock(weth).balanceOf(address(testContest)); // actual results console.log("expected reward:", distributionPerPlayer); console.log( "actual reward:", player1BalanceAfter - player1BalanceBefore ); console.log("Fund stucked:", fundStucked); } ``` then run `forge test --mt testUnfairDistributionInClosePot -vv` in the terminal and it will show following output: ```js [⠊] Compiling... [⠒] Compiling 1 files with Solc 0.8.20 [⠘] Solc 0.8.20 finished in 1.63s Compiler run successful! Ran 1 test for test/TestMyCut.t.sol:TestMyCut [PASS] testUnfairDistributionInClosePot() (gas: 905951) Logs: User Address: 0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D Contest Manager Address 1: 0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353 Minting tokens to: 0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D Approved tokens to: 0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353 expected reward: 540 actual reward: 180 Fund stucked: 360 Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.58ms (506.33µs CPU time) ``` ## Impact Loss of funds, Unfair distribution b/w users ## Recommendations Fix the functions as shown below: ```diff 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); - uint256 claimantCut = (remainingRewards - managerCut) / i_players.length; + uint256 totalClaimants = claimants.length; + if(totalClaimant == 0){ + _transferReward(msg.sender, remainingRewards - managerCut); + } else { + uint256 claimantCut = (remainingRewards - managerCut) / claimants.length; for (uint256 i = 0; i < claimants.length; i++) { _transferReward(claimants[i], claimantCut); } } + } } ```

Support

FAQs

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

Give us feedback!