Skip to content

Commit 0b4cb0c

Browse files
committed
test: added coverage for jumpDisputeKitID taking precendence over jumpDisputeKitIDOnCourtJump
1 parent 7df6109 commit 0b4cb0c

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

contracts/test/foundry/KlerosCore_Appeals.t.sol

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,4 +1667,173 @@ contract KlerosCore_AppealsTest is KlerosCore_TestBase {
16671667
round = core.getRoundInfo(disputeID, 1);
16681668
assertEq(round.drawnJurors.length, customNbVotes, "Should have drawn 9 jurors in Court2");
16691669
}
1670+
1671+
/// @dev Test that jumpDisputeKitID takes precedence over jumpDisputeKitIDOnCourtJump when both are set
1672+
function test_appeal_jumpDisputeKitIDTakesPrecedenceOverOnCourtJump() public {
1673+
uint256 disputeID = 0;
1674+
uint96 court2ID = 2;
1675+
uint96 court3ID = 3;
1676+
uint256 dkID2 = 2;
1677+
uint256 dkID3 = 3;
1678+
1679+
// Create DisputeKit2 and DisputeKit3
1680+
DisputeKitClassic dkLogic = new DisputeKitClassic();
1681+
1682+
bytes memory initDataDk2 = abi.encodeWithSignature(
1683+
"initialize(address,address,address)",
1684+
owner,
1685+
address(core),
1686+
address(wNative)
1687+
);
1688+
UUPSProxy proxyDk2 = new UUPSProxy(address(dkLogic), initDataDk2);
1689+
DisputeKitClassic disputeKit2 = DisputeKitClassic(address(proxyDk2));
1690+
1691+
bytes memory initDataDk3 = abi.encodeWithSignature(
1692+
"initialize(address,address,address)",
1693+
owner,
1694+
address(core),
1695+
address(wNative)
1696+
);
1697+
UUPSProxy proxyDk3 = new UUPSProxy(address(dkLogic), initDataDk3);
1698+
DisputeKitClassic disputeKit3 = DisputeKitClassic(address(proxyDk3));
1699+
1700+
vm.prank(owner);
1701+
core.addNewDisputeKit(disputeKit2);
1702+
vm.prank(owner);
1703+
core.addNewDisputeKit(disputeKit3);
1704+
1705+
// Create Court2 supporting all 3 DKs
1706+
uint256[] memory supportedDK = new uint256[](3);
1707+
supportedDK[0] = DISPUTE_KIT_CLASSIC;
1708+
supportedDK[1] = dkID2;
1709+
supportedDK[2] = dkID3;
1710+
vm.prank(owner);
1711+
core.createCourt(
1712+
GENERAL_COURT, // parent
1713+
hiddenVotes,
1714+
minStake,
1715+
alpha,
1716+
0.05 ether,
1717+
3, // Low jurorsForCourtJump to ensure jump
1718+
[uint256(60), uint256(120), uint256(180), uint256(240)],
1719+
sortitionExtraData,
1720+
supportedDK
1721+
);
1722+
1723+
// Create Court3 (sibling of Court2) also supporting all 3 DKs
1724+
vm.prank(owner);
1725+
core.createCourt(
1726+
GENERAL_COURT, // Same parent as Court2 (siblings)
1727+
hiddenVotes,
1728+
minStake,
1729+
alpha,
1730+
0.07 ether,
1731+
5,
1732+
[uint256(60), uint256(120), uint256(180), uint256(240)],
1733+
sortitionExtraData,
1734+
supportedDK
1735+
);
1736+
1737+
// CRITICAL: Configure NextRoundSettings with BOTH jumpDisputeKitID and jumpDisputeKitIDOnCourtJump set
1738+
// jumpDisputeKitID should take precedence
1739+
vm.prank(owner);
1740+
disputeKit3.changeNextRoundSettings(
1741+
court2ID,
1742+
DisputeKitClassicBase.NextRoundSettings({
1743+
enabled: true,
1744+
jumpCourtID: court3ID, // Force court jump to Court3
1745+
jumpDisputeKitID: dkID2, // Should be used (takes precedence)
1746+
jumpDisputeKitIDOnCourtJump: dkID3, // Should be IGNORED despite being set
1747+
nbVotes: 0
1748+
})
1749+
);
1750+
1751+
// Stake in courts
1752+
vm.prank(staker1);
1753+
core.setStake(court2ID, 20000);
1754+
vm.prank(staker1);
1755+
core.setStake(court3ID, 20000);
1756+
1757+
// Create dispute in Court2 with DisputeKit3
1758+
bytes memory extraData = abi.encodePacked(uint256(court2ID), DEFAULT_NB_OF_JURORS, dkID3);
1759+
arbitrable.changeArbitratorExtraData(extraData);
1760+
vm.prank(disputer);
1761+
arbitrable.createDispute{value: 0.05 ether * DEFAULT_NB_OF_JURORS}("Action");
1762+
1763+
vm.warp(block.timestamp + minStakingTime);
1764+
sortitionModule.passPhase(); // Generating
1765+
vm.warp(block.timestamp + rngLookahead);
1766+
sortitionModule.passPhase(); // Drawing
1767+
1768+
// Verify initial round uses DisputeKit3
1769+
KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
1770+
assertEq(round.disputeKitID, dkID3, "Initial round should use DisputeKit3");
1771+
1772+
core.draw(disputeID, DEFAULT_NB_OF_JURORS);
1773+
vm.warp(block.timestamp + timesPerPeriod[0]);
1774+
core.passPeriod(disputeID); // Vote
1775+
1776+
uint256[] memory voteIDs = new uint256[](3);
1777+
voteIDs[0] = 0;
1778+
voteIDs[1] = 1;
1779+
voteIDs[2] = 2;
1780+
vm.prank(staker1);
1781+
disputeKit3.castVote(disputeID, voteIDs, 2, 0, "XYZ");
1782+
1783+
core.passPeriod(disputeID); // Appeal
1784+
1785+
// CRITICAL TEST: Verify jump prediction shows DK2, NOT DK3
1786+
(uint96 nextCourtID, uint256 nextDisputeKitID, , bool isCourtJumping, bool isDisputeKitJumping) = core
1787+
.getCourtAndDisputeKitJumps(disputeID);
1788+
assertEq(nextCourtID, court3ID, "Should jump to Court3");
1789+
assertEq(nextDisputeKitID, dkID2, "Should jump to DisputeKit2 (jumpDisputeKitID), NOT DisputeKit3");
1790+
assertEq(isCourtJumping, true, "Should be court jumping");
1791+
assertEq(isDisputeKitJumping, true, "Should be DK jumping");
1792+
1793+
// Verify appealCost uses Court3's feeForJuror
1794+
uint256 expectedCost = 0.07 ether * 7; // 0.49 ether
1795+
assertEq(core.appealCost(disputeID), expectedCost, "appealCost should use Court3's fee");
1796+
1797+
// Fund and execute appeal
1798+
vm.prank(crowdfunder1);
1799+
disputeKit3.fundAppeal{value: 1.47 ether}(disputeID, 1);
1800+
1801+
// Verify events show jump to Court3 and DisputeKit2 (NOT DisputeKit3)
1802+
vm.expectEmit(true, true, true, true);
1803+
emit KlerosCore.CourtJump(disputeID, 1, court2ID, court3ID);
1804+
vm.expectEmit(true, true, true, true);
1805+
emit KlerosCore.DisputeKitJump(disputeID, 1, dkID3, dkID2); // DK3 -> DK2 (NOT DK3)
1806+
vm.expectEmit(true, true, true, true);
1807+
emit DisputeKitClassicBase.DisputeCreation(disputeID, 2, extraData);
1808+
vm.expectEmit(true, true, true, true);
1809+
emit KlerosCore.AppealDecision(disputeID, arbitrable);
1810+
vm.expectEmit(true, true, true, true);
1811+
emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.evidence);
1812+
vm.prank(crowdfunder2);
1813+
disputeKit3.fundAppeal{value: 0.98 ether}(disputeID, 2);
1814+
1815+
// Verify dispute is now in Court3 with DisputeKit2
1816+
(uint96 courtID, , , , ) = core.disputes(disputeID);
1817+
assertEq(courtID, court3ID, "Dispute should be in Court3");
1818+
1819+
round = core.getRoundInfo(disputeID, 1);
1820+
assertEq(round.disputeKitID, dkID2, "New round should use DisputeKit2 (NOT DisputeKit3)");
1821+
assertEq(round.nbVotes, 7, "New round should have 7 jurors");
1822+
1823+
// Verify DisputeKit3 is no longer active for this dispute
1824+
(, bool currentRound) = disputeKit3.coreDisputeIDToActive(disputeID);
1825+
assertEq(currentRound, false, "DisputeKit3 should no longer be active");
1826+
1827+
// Verify DisputeKit2 is now active
1828+
(, currentRound) = disputeKit2.coreDisputeIDToActive(disputeID);
1829+
assertEq(currentRound, true, "DisputeKit2 should be active");
1830+
1831+
// Verify we can draw jurors in the new DK
1832+
vm.expectEmit(true, true, true, true);
1833+
emit KlerosCore.Draw(staker1, disputeID, 1, 0);
1834+
core.draw(disputeID, 1);
1835+
1836+
(address account, , , ) = disputeKit2.getVoteInfo(disputeID, 1, 0);
1837+
assertEq(account, staker1, "Should have drawn juror in DisputeKit2");
1838+
}
16701839
}

0 commit comments

Comments
 (0)