Skip to content

Commit 5b35be9

Browse files
committed
Merge branch 'dev' into fix/dk-multiple-commits
2 parents df07fbb + 835d45b commit 5b35be9

File tree

7 files changed

+597
-5
lines changed

7 files changed

+597
-5
lines changed

contracts/src/arbitration/arbitrables/ArbitrableExample.sol

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ contract ArbitrableExample is IArbitrableV2 {
4040
mapping(uint256 => uint256) public externalIDtoLocalID; // Maps external (arbitrator side) dispute IDs to local dispute IDs.
4141
DisputeStruct[] public disputes; // Stores the disputes' info. disputes[disputeID].
4242

43+
uint256 public numberOfRulingOptions = 2;
44+
4345
// ************************************* //
4446
// * Function Modifiers * //
4547
// ************************************* //
@@ -100,6 +102,10 @@ contract ArbitrableExample is IArbitrableV2 {
100102
templateId = templateRegistry.setDisputeTemplate("", _templateData, _templateDataMappings);
101103
}
102104

105+
function changeNumberOfRulingOptions(uint256 _numberOfRulingOptions) external onlyByOwner {
106+
numberOfRulingOptions = _numberOfRulingOptions;
107+
}
108+
103109
// ************************************* //
104110
// * State Modifiers * //
105111
// ************************************* //
@@ -111,7 +117,6 @@ contract ArbitrableExample is IArbitrableV2 {
111117
function createDispute(string calldata _action) external payable returns (uint256 disputeID) {
112118
emit Action(_action);
113119

114-
uint256 numberOfRulingOptions = 2;
115120
uint256 localDisputeID = disputes.length;
116121
disputes.push(DisputeStruct({isRuled: false, ruling: 0, numberOfRulingOptions: numberOfRulingOptions}));
117122

@@ -130,7 +135,6 @@ contract ArbitrableExample is IArbitrableV2 {
130135
function createDispute(string calldata _action, uint256 _feeInWeth) external returns (uint256 disputeID) {
131136
emit Action(_action);
132137

133-
uint256 numberOfRulingOptions = 2;
134138
uint256 localDisputeID = disputes.length;
135139
disputes.push(DisputeStruct({isRuled: false, ruling: 0, numberOfRulingOptions: numberOfRulingOptions}));
136140

contracts/test/foundry/KlerosCore_Appeals.t.sol

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

contracts/test/foundry/KlerosCore_Disputes.t.sol

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ contract KlerosCore_DisputesTest is KlerosCore_TestBase {
9494
assertEq(jumped, false, "jumped should be false");
9595
assertEq(extraData, newExtraData, "Wrong extra data");
9696
assertEq(disputeKit.coreDisputeIDToLocal(0), disputeID, "Wrong local disputeID");
97-
assertEq(disputeKit.coreDisputeIDToActive(0), true, "Wrong disputes length");
97+
assertEq(disputeKit.coreDisputeIDToActive(0), true, "Dispute should be active in this DK");
9898

9999
(
100100
uint256 winningChoice,
@@ -146,4 +146,49 @@ contract KlerosCore_DisputesTest is KlerosCore_TestBase {
146146
assertEq(feeToken.balanceOf(address(core)), 0.18 ether, "Wrong token balance of the core");
147147
assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong token balance of the disputer");
148148
}
149+
150+
function testFuzz_createDispute_msgValue(uint256 disputeValue) public {
151+
uint256 disputeID = 0;
152+
uint256 arbitrationCost = core.arbitrationCost(arbitratorExtraData);
153+
154+
// Cap it to 10 eth, so the number of jurors is not astronomical.
155+
vm.assume(disputeValue >= arbitrationCost && disputeValue <= 10 ether);
156+
vm.deal(disputer, 10 ether);
157+
158+
vm.prank(staker1);
159+
core.setStake(GENERAL_COURT, 2000);
160+
vm.prank(disputer);
161+
arbitrable.createDispute{value: disputeValue}("Action");
162+
163+
KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
164+
assertEq(round.totalFeesForJurors, disputeValue, "Wrong totalFeesForJurors");
165+
assertEq(round.nbVotes, disputeValue / feeForJuror, "Wrong nbVotes");
166+
167+
vm.warp(block.timestamp + minStakingTime);
168+
sortitionModule.passPhase(); // Generating
169+
vm.warp(block.timestamp + rngLookahead);
170+
sortitionModule.passPhase(); // Drawing phase
171+
172+
core.draw(disputeID, disputeValue / feeForJuror);
173+
174+
vm.warp(block.timestamp + timesPerPeriod[0]);
175+
core.passPeriod(disputeID); // Vote
176+
177+
uint256[] memory voteIDs = new uint256[](disputeValue / feeForJuror);
178+
for (uint256 i = 0; i < voteIDs.length; i++) {
179+
voteIDs[i] = i;
180+
}
181+
182+
vm.prank(staker1);
183+
disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ");
184+
185+
core.passPeriod(disputeID); // Appeal
186+
187+
vm.warp(block.timestamp + timesPerPeriod[3]);
188+
core.passPeriod(disputeID); // Execution
189+
190+
vm.expectEmit(true, true, true, true);
191+
emit IArbitrableV2.Ruling(IArbitratorV2(address(core)), disputeID, 1);
192+
core.executeRuling(disputeID);
193+
}
149194
}

contracts/test/foundry/KlerosCore_Drawing.t.sol

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,90 @@ contract KlerosCore_DrawingTest is KlerosCore_TestBase {
121121
(, , , , uint256 nbVoters, ) = disputeKit.getRoundInfo(disputeID, roundID, 0);
122122
assertEq(nbVoters, 3, "nbVoters should be 3");
123123
}
124+
125+
function testFuzz_drawIterations(uint256 iterations) public {
126+
uint256 disputeID = 0;
127+
uint256 roundID = 0;
128+
129+
vm.prank(staker1);
130+
core.setStake(GENERAL_COURT, 2000);
131+
vm.prank(disputer);
132+
arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
133+
vm.warp(block.timestamp + minStakingTime);
134+
sortitionModule.passPhase(); // Generating
135+
vm.warp(block.timestamp + rngLookahead);
136+
sortitionModule.passPhase(); // Drawing phase
137+
138+
core.draw(disputeID, iterations);
139+
140+
uint256 iterationsCount;
141+
uint256 disputesWithoutJurors;
142+
if (iterations < DEFAULT_NB_OF_JURORS) {
143+
iterationsCount = iterations;
144+
disputesWithoutJurors = 1;
145+
} else {
146+
iterationsCount = DEFAULT_NB_OF_JURORS;
147+
disputesWithoutJurors = 0;
148+
}
149+
150+
KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
151+
assertEq(round.drawIterations, iterationsCount, "Wrong drawIterations number");
152+
assertEq(round.nbVotes, DEFAULT_NB_OF_JURORS, "Wrong nbVotes");
153+
154+
(uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
155+
staker1,
156+
GENERAL_COURT
157+
);
158+
uint256 pnkAtStake = (minStake * alpha) / ONE_BASIS_POINT;
159+
assertEq(totalStaked, 2000, "Wrong amount total staked");
160+
assertEq(totalLocked, pnkAtStake * iterationsCount, "Wrong amount locked"); // 1000 per draw
161+
assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
162+
assertEq(sortitionModule.disputesWithoutJurors(), disputesWithoutJurors, "Wrong disputesWithoutJurors count");
163+
}
164+
165+
function testFuzz_drawIterations_nbJurors(uint256 iterations, uint256 disputeValue) public {
166+
uint256 disputeID = 0;
167+
uint256 roundID = 0;
168+
169+
uint256 arbitrationCost = core.arbitrationCost(arbitratorExtraData);
170+
// Cap it to 10 eth, so the number of jurors is not astronomical.
171+
vm.assume(disputeValue >= arbitrationCost && disputeValue <= 10 ether);
172+
vm.deal(disputer, 10 ether);
173+
174+
vm.prank(staker1);
175+
core.setStake(GENERAL_COURT, 2000);
176+
vm.prank(disputer);
177+
arbitrable.createDispute{value: disputeValue}("Action");
178+
vm.warp(block.timestamp + minStakingTime);
179+
sortitionModule.passPhase(); // Generating
180+
vm.warp(block.timestamp + rngLookahead);
181+
sortitionModule.passPhase(); // Drawing phase
182+
183+
core.draw(disputeID, iterations);
184+
185+
KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
186+
assertEq(round.totalFeesForJurors, disputeValue, "Wrong totalFeesForJurors");
187+
assertEq(round.nbVotes, disputeValue / feeForJuror, "Wrong nbVotes");
188+
189+
uint256 iterationsCount;
190+
uint256 disputesWithoutJurors;
191+
if (iterations < round.nbVotes) {
192+
iterationsCount = iterations;
193+
disputesWithoutJurors = 1;
194+
} else {
195+
iterationsCount = round.nbVotes;
196+
disputesWithoutJurors = 0;
197+
}
198+
199+
assertEq(round.drawIterations, iterationsCount, "Wrong drawIterations number");
200+
(uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
201+
staker1,
202+
GENERAL_COURT
203+
);
204+
uint256 pnkAtStake = (minStake * alpha) / ONE_BASIS_POINT;
205+
assertEq(totalStaked, 2000, "Wrong amount total staked");
206+
assertEq(totalLocked, pnkAtStake * iterationsCount, "Wrong amount locked");
207+
assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
208+
assertEq(sortitionModule.disputesWithoutJurors(), disputesWithoutJurors, "Wrong disputesWithoutJurors count");
209+
}
124210
}

0 commit comments

Comments
 (0)