@@ -8,6 +8,7 @@ import {DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeK
88import {IArbitratorV2, IArbitrableV2} from "../../src/arbitration/KlerosCore.sol " ;
99import {IERC20 } from "../../src/libraries/SafeERC20.sol " ;
1010import "../../src/libraries/Constants.sol " ;
11+ import {console} from "forge-std/console.sol " ;
1112
1213/// @title KlerosCore_ExecutionTest
1314/// @dev Tests for KlerosCore execution, rewards, and ruling finalization
@@ -96,6 +97,9 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
9697 "Wrong penalty coherence 2 vote ID "
9798 );
9899
100+ assertEq (pinakion.balanceOf (address (core)), 22000 , "Wrong token balance of the core " );
101+ assertEq (sortitionModule.totalStaked (), 22000 , "Total staked should be equal to the balance in this test " );
102+
99103 vm.expectEmit (true , true , true , true );
100104 emit SortitionModule.StakeLocked (staker1, 1000 , true );
101105 vm.expectEmit (true , true , true , true );
@@ -141,9 +145,11 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
141145 assertEq (staker1.balance, 0 , "Wrong balance of the staker1 " );
142146 assertEq (staker2.balance, 0.09 ether, "Wrong balance of the staker2 " );
143147
144- assertEq (pinakion.balanceOf (address (core)), 22000 , "Wrong token balance of the core " ); // Was 21500. 1000 was transferred to staker2
148+ assertEq (pinakion.balanceOf (address (core)), 22000 , "Token balance of the core shouldn't change after rewards " );
149+ assertEq (sortitionModule.totalStaked (), 22000 , "Total staked shouldn't change after rewards " );
150+
145151 assertEq (pinakion.balanceOf (staker1), 999999999999998000 , "Wrong token balance of staker1 " );
146- assertEq (pinakion.balanceOf (staker2), 999999999999980000 , "Wrong token balance of staker2 " ); // 20k stake and 1k added as a reward, thus -19k from the default
152+ assertEq (pinakion.balanceOf (staker2), 999999999999980000 , "Wrong token balance of staker2 " );
147153 }
148154
149155 function test_execute_NoCoherence () public {
@@ -477,13 +483,19 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
477483 vm.prank (owner);
478484 core.transferBySortitionModule (staker1, 1000 );
479485
486+ assertEq (pinakion.balanceOf (address (core)), 1000 , "Wrong token balance of the core " );
487+ assertEq (sortitionModule.totalStaked (), 1000 , "Wrong totalStaked before withdrawal " );
488+
480489 vm.expectEmit (true , true , true , true );
481490 emit SortitionModule.LeftoverPNKWithdrawn (staker1, 1000 );
482491 sortitionModule.withdrawLeftoverPNK (staker1);
483492
484493 (totalStaked, , , ) = sortitionModule.getJurorBalance (staker1, GENERAL_COURT);
485494 assertEq (totalStaked, 0 , "Should be unstaked fully " );
486495
496+ assertEq (pinakion.balanceOf (address (core)), 0 , "Wrong token balance of the core " );
497+ assertEq (sortitionModule.totalStaked (), 0 , "Wrong totalStaked after withdrawal " );
498+
487499 // Check that everything is withdrawn now
488500 assertEq (pinakion.balanceOf (address (core)), 0 , "Core balance should be empty " );
489501 assertEq (pinakion.balanceOf (staker1), 1 ether, "All PNK should be withdrawn " );
@@ -749,6 +761,52 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
749761 assertEq (address (disputeKit).balance, 0 , "Wrong balance of the DK " );
750762 }
751763
764+ function test_inflatedTotalStaked_whenDelayedStakeExecute_whenJurorHasNoFunds () public {
765+ // pre conditions
766+ // 1. there is a dispute in drawing phase
767+ // 2. juror call setStake with an amount greater than his PNK balance
768+ // 3. draw jurors, move to voting phase and execute voting
769+ // 4. move sortition to staking phase
770+ uint256 disputeID = 0 ;
771+ uint256 amountToStake = 20000 ;
772+ _stakePnk_createDispute_moveToDrawingPhase (disputeID, staker1, amountToStake);
773+
774+ KlerosCore.Round memory round = core.getRoundInfo (disputeID, 0 );
775+ uint256 pnkAtStakePerJuror = round.pnkAtStakePerJuror;
776+ _stakeBalanceForJuror (staker1, type (uint256 ).max);
777+ _drawJurors_advancePeriodToVoting (disputeID);
778+ _vote_execute (disputeID, staker1);
779+ sortitionModule.passPhase (); // set it to staking phase
780+ _assertJurorBalance (
781+ disputeID,
782+ staker1,
783+ amountToStake,
784+ pnkAtStakePerJuror * DEFAULT_NB_OF_JURORS,
785+ amountToStake,
786+ 1
787+ );
788+
789+ console.log ("totalStaked before: %e " , sortitionModule.totalStaked ());
790+
791+ // execution: execute delayed stake
792+ sortitionModule.executeDelayedStakes (1 );
793+
794+ // post condition: inflated totalStaked
795+ console.log ("totalStaked after: %e " , sortitionModule.totalStaked ());
796+ _assertJurorBalance (
797+ disputeID,
798+ staker1,
799+ amountToStake,
800+ pnkAtStakePerJuror * DEFAULT_NB_OF_JURORS,
801+ amountToStake,
802+ 1
803+ );
804+
805+ // new juror tries to stake but totalStaked already reached type(uint256).max
806+ // it reverts with "arithmetic underflow or overflow (0x11)"
807+ _stakeBalanceForJuror (staker2, 20000 );
808+ }
809+
752810 function testFuzz_executeIterations (uint256 iterations ) public {
753811 uint256 disputeID = 0 ;
754812 uint256 roundID = 0 ;
@@ -847,4 +905,61 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
847905 assertEq (totalLocked, (pnkAtStake * nbJurors) - unlockedTokens, "Wrong amount locked " );
848906 assertEq (stakedInCourt, 2000 , "Wrong amount staked in court " );
849907 }
908+
909+ ///////// Internal //////////
910+
911+ function _assertJurorBalance (
912+ uint256 disputeID ,
913+ address juror ,
914+ uint256 totalStakedPnk ,
915+ uint256 totalLocked ,
916+ uint256 stakedInCourt ,
917+ uint256 nbCourts
918+ ) internal {
919+ (uint256 totalStakedPnk , uint256 totalLocked , uint256 stakedInCourt , uint256 nbCourts ) = sortitionModule
920+ .getJurorBalance (juror, GENERAL_COURT);
921+ assertEq (totalStakedPnk, totalStakedPnk, "Wrong totalStakedPnk " ); // jurors total staked a.k.a juror.stakedPnk
922+ assertEq (totalLocked, totalLocked, "Wrong totalLocked " );
923+ assertEq (stakedInCourt, stakedInCourt, "Wrong stakedInCourt " ); // juror staked in court a.k.a _stakeOf
924+ assertEq (nbCourts, nbCourts, "Wrong nbCourts " );
925+ }
926+
927+ function _stakeBalanceForJuror (address juror , uint256 amount ) internal {
928+ console.log ("actual juror PNK balance before staking: %e " , pinakion.balanceOf (juror));
929+ vm.prank (juror);
930+ core.setStake (GENERAL_COURT, amount);
931+ }
932+
933+ function _stakePnk_createDispute_moveToDrawingPhase (uint256 disputeID , address juror , uint256 amount ) internal {
934+ vm.prank (juror);
935+ core.setStake (GENERAL_COURT, amount);
936+ vm.prank (disputer);
937+ arbitrable.createDispute {value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action " );
938+ vm.warp (block .timestamp + minStakingTime);
939+ sortitionModule.passPhase (); // Generating
940+ vm.warp (block .timestamp + rngLookahead);
941+ sortitionModule.passPhase (); // Drawing phase
942+
943+ assertEq (sortitionModule.totalStaked (), amount, "!totalStaked " );
944+ }
945+
946+ function _drawJurors_advancePeriodToVoting (uint256 disputeID ) internal {
947+ core.draw (disputeID, DEFAULT_NB_OF_JURORS);
948+ vm.warp (block .timestamp + timesPerPeriod[0 ]);
949+ core.passPeriod (disputeID); // Vote
950+ }
951+
952+ function _vote_execute (uint256 disputeID , address juror ) internal {
953+ uint256 [] memory voteIDs = new uint256 [](3 );
954+ voteIDs[0 ] = 0 ;
955+ voteIDs[1 ] = 1 ;
956+ voteIDs[2 ] = 2 ;
957+
958+ vm.prank (juror);
959+ disputeKit.castVote (disputeID, voteIDs, 2 , 0 , "XYZ " );
960+ core.passPeriod (disputeID); // Appeal
961+
962+ vm.warp (block .timestamp + timesPerPeriod[3 ]);
963+ core.passPeriod (disputeID); // Execution
964+ }
850965}
0 commit comments