@@ -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
@@ -749,6 +750,52 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
749750 assertEq (address (disputeKit).balance, 0 , "Wrong balance of the DK " );
750751 }
751752
753+ function test_inflatedTotalStaked_whenDelayedStakeExecute_whenJurorHasNoFunds () public {
754+ // pre conditions
755+ // 1. there is a dispute in drawing phase
756+ // 2. juror call setStake with an amount greater than his PNK balance
757+ // 3. draw jurors, move to voting phase and execute voting
758+ // 4. move sortition to staking phase
759+ uint256 disputeID = 0 ;
760+ uint256 amountToStake = 20000 ;
761+ _stakePnk_createDispute_moveToDrawingPhase (disputeID, staker1, amountToStake);
762+
763+ KlerosCore.Round memory round = core.getRoundInfo (disputeID, 0 );
764+ uint256 pnkAtStakePerJuror = round.pnkAtStakePerJuror;
765+ _stakeBalanceForJuror (staker1, type (uint256 ).max);
766+ _drawJurors_advancePeriodToVoting (disputeID);
767+ _vote_execute (disputeID, staker1);
768+ sortitionModule.passPhase (); // set it to staking phase
769+ _assertJurorBalance (
770+ disputeID,
771+ staker1,
772+ amountToStake,
773+ pnkAtStakePerJuror * DEFAULT_NB_OF_JURORS,
774+ amountToStake,
775+ 1
776+ );
777+
778+ console.log ("totalStaked before: %e " , sortitionModule.totalStaked ());
779+
780+ // execution: execute delayed stake
781+ sortitionModule.executeDelayedStakes (1 );
782+
783+ // post condition: inflated totalStaked
784+ console.log ("totalStaked after: %e " , sortitionModule.totalStaked ());
785+ _assertJurorBalance (
786+ disputeID,
787+ staker1,
788+ amountToStake,
789+ pnkAtStakePerJuror * DEFAULT_NB_OF_JURORS,
790+ amountToStake,
791+ 1
792+ );
793+
794+ // new juror tries to stake but totalStaked already reached type(uint256).max
795+ // it reverts with "arithmetic underflow or overflow (0x11)"
796+ _stakeBalanceForJuror (staker2, 20000 );
797+ }
798+
752799 function testFuzz_executeIterations (uint256 iterations ) public {
753800 uint256 disputeID = 0 ;
754801 uint256 roundID = 0 ;
@@ -847,4 +894,61 @@ contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
847894 assertEq (totalLocked, (pnkAtStake * nbJurors) - unlockedTokens, "Wrong amount locked " );
848895 assertEq (stakedInCourt, 2000 , "Wrong amount staked in court " );
849896 }
897+
898+ ///////// Internal //////////
899+
900+ function _assertJurorBalance (
901+ uint256 disputeID ,
902+ address juror ,
903+ uint256 totalStakedPnk ,
904+ uint256 totalLocked ,
905+ uint256 stakedInCourt ,
906+ uint256 nbCourts
907+ ) internal {
908+ (uint256 totalStakedPnk , uint256 totalLocked , uint256 stakedInCourt , uint256 nbCourts ) = sortitionModule
909+ .getJurorBalance (juror, GENERAL_COURT);
910+ assertEq (totalStakedPnk, totalStakedPnk, "Wrong totalStakedPnk " ); // jurors total staked a.k.a juror.stakedPnk
911+ assertEq (totalLocked, totalLocked, "Wrong totalLocked " );
912+ assertEq (stakedInCourt, stakedInCourt, "Wrong stakedInCourt " ); // juror staked in court a.k.a _stakeOf
913+ assertEq (nbCourts, nbCourts, "Wrong nbCourts " );
914+ }
915+
916+ function _stakeBalanceForJuror (address juror , uint256 amount ) internal {
917+ console.log ("actual juror PNK balance before staking: %e " , pinakion.balanceOf (juror));
918+ vm.prank (juror);
919+ core.setStake (GENERAL_COURT, amount);
920+ }
921+
922+ function _stakePnk_createDispute_moveToDrawingPhase (uint256 disputeID , address juror , uint256 amount ) internal {
923+ vm.prank (juror);
924+ core.setStake (GENERAL_COURT, amount);
925+ vm.prank (disputer);
926+ arbitrable.createDispute {value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action " );
927+ vm.warp (block .timestamp + minStakingTime);
928+ sortitionModule.passPhase (); // Generating
929+ vm.warp (block .timestamp + rngLookahead);
930+ sortitionModule.passPhase (); // Drawing phase
931+
932+ assertEq (sortitionModule.totalStaked (), amount, "!totalStaked " );
933+ }
934+
935+ function _drawJurors_advancePeriodToVoting (uint256 disputeID ) internal {
936+ core.draw (disputeID, DEFAULT_NB_OF_JURORS);
937+ vm.warp (block .timestamp + timesPerPeriod[0 ]);
938+ core.passPeriod (disputeID); // Vote
939+ }
940+
941+ function _vote_execute (uint256 disputeID , address juror ) internal {
942+ uint256 [] memory voteIDs = new uint256 [](3 );
943+ voteIDs[0 ] = 0 ;
944+ voteIDs[1 ] = 1 ;
945+ voteIDs[2 ] = 2 ;
946+
947+ vm.prank (juror);
948+ disputeKit.castVote (disputeID, voteIDs, 2 , 0 , "XYZ " );
949+ core.passPeriod (disputeID); // Appeal
950+
951+ vm.warp (block .timestamp + timesPerPeriod[3 ]);
952+ core.passPeriod (disputeID); // Execution
953+ }
850954}
0 commit comments