@@ -500,4 +500,130 @@ contract KlerosCore_AppealsTest is KlerosCore_TestBase {
500500 emit KlerosCore.NewPeriod (disputeID, KlerosCore.Period.execution);
501501 core.passPeriod (disputeID);
502502 }
503+
504+ function testFuzz_appeal (uint256 numberOfOptions , uint256 choice1 , uint256 choice2 , uint256 choice3 ) public {
505+ uint256 disputeID = 0 ;
506+
507+ arbitrable.changeNumberOfRulingOptions (numberOfOptions);
508+
509+ // Have only 2 options for 3 jurors to create a majority
510+ vm.assume (choice1 <= numberOfOptions);
511+ vm.assume (choice2 <= numberOfOptions);
512+ vm.assume (choice3 <= numberOfOptions); // Will be used for appeal
513+
514+ vm.prank (staker1);
515+ core.setStake (GENERAL_COURT, 2000 );
516+ vm.prank (disputer);
517+ arbitrable.createDispute {value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action " );
518+
519+ (uint256 numberOfChoices , , ) = disputeKit.disputes (disputeID);
520+
521+ assertEq (numberOfChoices, numberOfOptions, "Wrong numberOfChoices " );
522+
523+ vm.warp (block .timestamp + minStakingTime);
524+ sortitionModule.passPhase (); // Generating
525+ vm.warp (block .timestamp + rngLookahead);
526+ sortitionModule.passPhase (); // Drawing phase
527+
528+ // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
529+ core.draw (disputeID, 1 );
530+
531+ vm.warp (block .timestamp + maxDrawingTime);
532+ sortitionModule.passPhase (); // Staking phase to stake the 2nd voter
533+ vm.prank (staker2);
534+ core.setStake (GENERAL_COURT, 20000 );
535+ vm.warp (block .timestamp + minStakingTime);
536+ sortitionModule.passPhase (); // Generating
537+ vm.warp (block .timestamp + rngLookahead);
538+ sortitionModule.passPhase (); // Drawing phase
539+
540+ core.draw (disputeID, 2 ); // Assign leftover votes to staker2
541+
542+ vm.warp (block .timestamp + timesPerPeriod[0 ]);
543+ core.passPeriod (disputeID); // Vote
544+
545+ uint256 [] memory voteIDs = new uint256 [](1 );
546+ voteIDs[0 ] = 0 ;
547+ vm.prank (staker1);
548+ disputeKit.castVote (disputeID, voteIDs, choice1, 0 , "XYZ " ); // Staker1 only got 1 vote because of low stake
549+
550+ voteIDs = new uint256 [](2 );
551+ voteIDs[0 ] = 1 ;
552+ voteIDs[1 ] = 2 ;
553+ vm.prank (staker2);
554+ disputeKit.castVote (disputeID, voteIDs, choice2, 0 , "XYZ " );
555+ core.passPeriod (disputeID); // Appeal
556+
557+ vm.assume (choice3 != choice2);
558+ vm.prank (crowdfunder1);
559+ disputeKit.fundAppeal {value: 0.63 ether }(disputeID, choice3); // Fund the losing choice. Total cost will be 0.63 (0.21 + 0.21 * (20000/10000))
560+
561+ assertEq ((disputeKit.getFundedChoices (disputeID)).length , 1 , "1 choice should be funded " );
562+
563+ vm.prank (crowdfunder1);
564+ disputeKit.fundAppeal {value: 0.42 ether }(disputeID, choice2); // Fund the winning choice. Total cost will be 0.42 (0.21 + 0.21 * (10000/10000))
565+
566+ assertEq ((disputeKit.getFundedChoices (disputeID)).length , 0 , "No funded choices in a fresh round " );
567+ }
568+
569+ function testFuzz_fundAppeal_msgValue (uint256 appealValue ) public {
570+ uint256 disputeID = 0 ;
571+
572+ vm.assume (appealValue <= 10 ether);
573+ vm.deal (crowdfunder1, 10 ether);
574+
575+ vm.prank (staker1);
576+ core.setStake (GENERAL_COURT, 2000 );
577+ vm.prank (disputer);
578+ arbitrable.createDispute {value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action " );
579+
580+ vm.warp (block .timestamp + minStakingTime);
581+ sortitionModule.passPhase (); // Generating
582+ vm.warp (block .timestamp + rngLookahead);
583+ sortitionModule.passPhase (); // Drawing phase
584+
585+ // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
586+ core.draw (disputeID, 1 );
587+
588+ vm.warp (block .timestamp + maxDrawingTime);
589+ sortitionModule.passPhase (); // Staking phase to stake the 2nd voter
590+ vm.prank (staker2);
591+ core.setStake (GENERAL_COURT, 20000 );
592+ vm.warp (block .timestamp + minStakingTime);
593+ sortitionModule.passPhase (); // Generating
594+ vm.warp (block .timestamp + rngLookahead);
595+ sortitionModule.passPhase (); // Drawing phase
596+
597+ core.draw (disputeID, 2 ); // Assign leftover votes to staker2
598+
599+ vm.warp (block .timestamp + timesPerPeriod[0 ]);
600+ core.passPeriod (disputeID); // Vote
601+
602+ uint256 [] memory voteIDs = new uint256 [](1 );
603+ voteIDs[0 ] = 0 ;
604+ vm.prank (staker1);
605+ disputeKit.castVote (disputeID, voteIDs, 1 , 0 , "XYZ " ); // Staker1 only got 1 vote because of low stake
606+
607+ voteIDs = new uint256 [](2 );
608+ voteIDs[0 ] = 1 ;
609+ voteIDs[1 ] = 2 ;
610+ vm.prank (staker2);
611+ disputeKit.castVote (disputeID, voteIDs, 2 , 0 , "XYZ " );
612+ core.passPeriod (disputeID); // Appeal
613+
614+ vm.prank (crowdfunder1);
615+ disputeKit.fundAppeal {value: appealValue}(disputeID, 1 ); // Fund the losing choice
616+
617+ if (appealValue >= 0.63 ether) {
618+ // 0.63 eth is the required amount for losing side.
619+ assertEq ((disputeKit.getFundedChoices (disputeID)).length , 1 , "One choice should be funded " );
620+ // Dispute kit shouldn't demand more value than necessary
621+ assertEq (crowdfunder1.balance, 9.37 ether, "Wrong balance of the crowdfunder " );
622+ assertEq (address (disputeKit).balance, 0.63 ether, "Wrong balance of the DK " );
623+ } else {
624+ assertEq ((disputeKit.getFundedChoices (disputeID)).length , 0 , "No choices should be funded " );
625+ assertEq (crowdfunder1.balance, 10 ether - appealValue, "Wrong balance of the crowdfunder " );
626+ assertEq (address (disputeKit).balance, appealValue, "Wrong balance of the DK " );
627+ }
628+ }
503629}
0 commit comments