Similarly, rounding errors can occur while calculating each claimant's cut, potentially leading to underpayment due to truncation. While this works against the favor of the user, it can still result in dissatisfaction and potential disputes if claimants
feel they are not receiving their fair share.
If the remaining funds are not evenly divisible by the number of claimants, the truncation could result in under-distribution, leading some funds undistributed.
function testClaimantGetsUnfairZeroShare() public mintAndApproveTokens {
vm.startPrank(user);
rewards = [2, 2, 2];
totalRewards = 6;
contest = ContestManager(conMan).createContest(players, rewards, IERC20(ERC20Mock(weth)), totalRewards);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
vm.startPrank(player1);
Pot(contest).claimCut();
vm.stopPrank();
vm.startPrank(player2);
Pot(contest).claimCut();
vm.stopPrank();
vm.startPrank(player3);
Pot(contest).claimCut();
vm.stopPrank();
uint256 claimantBalanceBefore1 = ERC20Mock(weth).balanceOf(player1);
uint256 claimantBalanceBefore2 = ERC20Mock(weth).balanceOf(player2);
uint256 claimantBalanceBefore3 = ERC20Mock(weth).balanceOf(player3);
vm.warp(91 days);
vm.startPrank(user);
ContestManager(conMan).closeContest(contest);
vm.stopPrank();
uint256 claimantBalanceAfter1 = ERC20Mock(weth).balanceOf(player1);
uint256 claimantBalanceAfter2 = ERC20Mock(weth).balanceOf(player2);
uint256 claimantBalanceAfter3 = ERC20Mock(weth).balanceOf(player3);
console.log("This is the claimantBalanceBefore1::", claimantBalanceBefore1);
console.log("This is the claimantBalanceBefore2::", claimantBalanceBefore2);
console.log("This is the claimantBalanceBefore3::", claimantBalanceBefore3);
console.log("This is the claimantBalanceAfter1::", claimantBalanceAfter1);
console.log("This is the claimantBalanceAfter2::", claimantBalanceAfter2);
console.log("This is the claimantBalanceAfter3::", claimantBalanceAfter3);
}
Traces:
[1723902] TestMyCut::setUp()
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return]
├─ [1103083] → new ContestManager@0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353
│ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return] 5391 bytes of code
├─ [517943] → new ERC20Mock@0x5929B14F2984bBE5309c2eC9E7819060C31c970f
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38], value: 100000000000 [1e11])
│ └─ ← [Return] 2124 bytes of code
├─ [0] console::log("User Address: ", user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("Contest Manager Address 1: ", ContestManager: [0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353]) [staticcall]
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
└─ ← [Stop]
[1076746] TestMyCut::testClaimantGetsUnfairZeroShare()
├─ [0] console::log("Minting tokens to: ", user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D]) [staticcall]
│ └─ ← [Stop]
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return]
├─ [29712] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 1000000000000000000000 [1e21])
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 1000000000000000000000 [1e21])
│ └─ ← [Stop]
├─ [24739] ERC20Mock::approve(ContestManager: [0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353], 1000000000000000000000 [1e21])
│ ├─ emit Approval(owner: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], spender: ContestManager: [0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353], value: 1000000000000000000000 [1e21])
│ └─ ← [Return] true
├─ [0] console::log("Approved tokens to: ", ContestManager: [0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353]) [staticcall]
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return]
├─ [702007] ContestManager::createContest([0x7026B763CBE7d4E72049EA67E89326432a50ef84, 0xEb0A3b7B96C1883858292F0039161abD287E3324, 0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3], [2, 2, 2], ERC20Mock: [0x5929B14F2984bBE5309c2eC9E7819060C31c970f], 6)
│ ├─ [597792] → new Pot@0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0
│ │ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: ContestManager: [0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353])
│ │ └─ ← [Return] 1513 bytes of code
│ └─ ← [Return] Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0]
├─ [29108] ContestManager::fundContest(0)
│ ├─ [192] Pot::getToken() [staticcall]
│ │ └─ ← [Return] ERC20Mock: [0x5929B14F2984bBE5309c2eC9E7819060C31c970f]
│ ├─ [641] ERC20Mock::balanceOf(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D]) [staticcall]
│ │ └─ ← [Return] 1000000000000000000000 [1e21]
│ ├─ [26084] ERC20Mock::transferFrom(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0], 6)
│ │ ├─ emit Transfer(from: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], to: Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0], value: 6)
│ │ └─ ← [Return] true
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::startPrank(player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84])
│ └─ ← [Return]
├─ [70849] Pot::claimCut()
│ ├─ [25188] ERC20Mock::transfer(player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84], 2)
│ │ ├─ emit Transfer(from: Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0], to: player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84], value: 2)
│ │ └─ ← [Return] true
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::startPrank(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324])
│ └─ ← [Return]
├─ [48949] Pot::claimCut()
│ ├─ [25188] ERC20Mock::transfer(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324], 2)
│ │ ├─ emit Transfer(from: Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0], to: player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324], value: 2)
│ │ └─ ← [Return] true
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::startPrank(player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3])
│ └─ ← [Return]
├─ [48949] Pot::claimCut()
│ ├─ [25188] ERC20Mock::transfer(player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3], 2)
│ │ ├─ emit Transfer(from: Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0], to: player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3], value: 2)
│ │ └─ ← [Return] true
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [641] ERC20Mock::balanceOf(player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84]) [staticcall]
│ └─ ← [Return] 2
├─ [641] ERC20Mock::balanceOf(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324]) [staticcall]
│ └─ ← [Return] 2
├─ [641] ERC20Mock::balanceOf(player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3]) [staticcall]
│ └─ ← [Return] 2
├─ [0] VM::warp(7862400 [7.862e6])
│ └─ ← [Return]
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return]
├─ [1425] ContestManager::closeContest(Pot: [0x43e82d2718cA9eEF545A591dfbfD2035CD3eF9c0])
│ ├─ [570] Pot::closePot()
│ │ └─ ← [Stop]
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [641] ERC20Mock::balanceOf(player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84]) [staticcall]
│ └─ ← [Return] 2
├─ [641] ERC20Mock::balanceOf(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324]) [staticcall]
│ └─ ← [Return] 2
├─ [641] ERC20Mock::balanceOf(player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3]) [staticcall]
│ └─ ← [Return] 2
├─ [0] console::log("This is the claimantBalanceBefore1::", 2) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("This is the claimantBalanceBefore2::", 2) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("This is the claimantBalanceBefore3::", 2) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("This is the claimantBalanceAfter1::", 2) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("This is the claimantBalanceAfter2::", 2) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("This is the claimantBalanceAfter3::", 2) [staticcall]
│ └─ ← [Stop]
└─ ← [Stop]
From above, we all know that the manager cut gets truncated to 0.
So this how the formula works it out...