@@ -500,4 +500,130 @@ contract KlerosCore_AppealsTest is KlerosCore_TestBase {
500
500
emit KlerosCore.NewPeriod (disputeID, KlerosCore.Period.execution);
501
501
core.passPeriod (disputeID);
502
502
}
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
+ }
503
629
}
0 commit comments