Skip to content

Conversation

jaybuidl
Copy link
Member

@jaybuidl jaybuidl commented Oct 21, 2025

PR-Codex overview

This PR focuses on simplifying the initialization of various DisputeKit contracts by removing unnecessary parameters and enhancing the dispute kit's jumping mechanism in the Kleros arbitration system.

Detailed summary

  • Removed _jumpDisputeKitID from initialize functions in DisputeKitClassic, DisputeKitShutter, DisputeKitGated, and DisputeKitGatedShutter.
  • Updated deployment arguments for DisputeKitClassic, DisputeKitShutter, DisputeKitGated, and DisputeKitGatedShutter to exclude _jumpDisputeKitID.
  • Enhanced IDisputeKit interface with getCourtAndDisputeKitJumps method.
  • Introduced NextRoundSettings struct in DisputeKitClassicBase for managing next round settings.
  • Refactored changeJumpDisputeKitID method to changeNextRoundSettings in DisputeKitClassicBase.
  • Updated internal logic in KlerosCore for handling dispute kit and court jumps, ensuring compatibility checks.
  • Removed legacy functions and simplified dispute kit jump logic in KlerosCore.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added a public getter to report next court/dispute-kit targets, vote count, and jump flags.
    • Draw operation now also returns the originating subcourt identifier.
  • Refactor

    • Centralized and simplified dispute-kit/court jump logic to use multi-value results.
    • Standardized and simplified dispute-kit initialization across variants.
  • Chore

    • Increased compiler optimizer runs for builds.

@jaybuidl jaybuidl self-assigned this Oct 21, 2025
@jaybuidl jaybuidl added Type: Feature🗿 Compatibility: ABI change 🗯 Smart contract ABI is changing. Package: Contracts Court smart contracts labels Oct 21, 2025
@netlify
Copy link

netlify bot commented Oct 21, 2025

Deploy Preview for kleros-v2-neo ready!

Name Link
🔨 Latest commit 973f572
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-neo/deploys/68f7cfde1e59af0008f7a7a8
😎 Deploy Preview https://deploy-preview-2187--kleros-v2-neo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Oct 21, 2025

Deploy Preview for kleros-v2-testnet ready!

Name Link
🔨 Latest commit 973f572
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet/deploys/68f7cfdebe522500087c2a45
😎 Deploy Preview https://deploy-preview-2187--kleros-v2-testnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Oct 21, 2025

Deploy Preview for kleros-v2-testnet-devtools failed. Why did it fail? →

Name Link
🔨 Latest commit 973f572
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet-devtools/deploys/68f7cfde2e8eff00089625ce

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 21, 2025

Walkthrough

Refactors dispute-kit jump handling: replaces a global jumpDisputeKitID with per-court NextRoundSettings (courtIDToNextRoundSettings), adds getCourtAndDisputeKitJumps (expanded return values), updates draw return signature, and removes _jumpDisputeKitID initializer args across dispute-kit implementations and deployments.

Changes

Cohort / File(s) Summary
Config
contracts/hardhat.config.ts
Increased Solidity optimizer runs from 800 to 1000.
Core Arbitration
contracts/src/arbitration/KlerosCore.sol
Added external getCourtAndDisputeKitJumps (returns newCourtID, newDisputeKitID, newRoundNbVotes, courtJump, disputeKitJump); updated internal _getCourtAndDisputeKitJumps to return expanded set and enforce compatibility fallback to classic DK; removed isDisputeKitJumping.
DisputeKit Base
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
Replaced global jumpDisputeKitID with courtIDToNextRoundSettings mapping and NextRoundSettings struct; added changeNextRoundSettings; added getCourtAndDisputeKitJumps public function; removed legacy jump helpers (getJumpDisputeKitID, earlyCourtJump, getNbVotesAfterAppeal); initializer no longer accepts _jumpDisputeKitID.
DisputeKit Implementations
contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol, .../DisputeKitGated.sol, .../DisputeKitGatedShutter.sol, .../DisputeKitShutter.sol, .../DisputeKitSybilResistant.sol
Removed _jumpDisputeKitID parameter from initialize signatures and corresponding base initializer calls.
DisputeKit Interface
contracts/src/arbitration/interfaces/IDisputeKit.sol
Extended draw to return (address drawnAddress, uint96 fromSubcourtID); added getCourtAndDisputeKitJumps; removed earlyCourtJump, getNbVotesAfterAppeal, and getJumpDisputeKitID.
Deployments / Tests
contracts/deploy/00-home-chain-arbitration*.ts, contracts/test/arbitration/helpers/*
Shortened deployment / test initializer arg lists for multiple dispute-kit deployments (removed classic/dispute-kit ID arg); updated related test helpers to pass fewer args.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant KlerosCore
    participant DisputeKitBase

    rect rgba(200,230,255,0.4)
    Note over User,KlerosCore: Appeal / fundAppeal flow (new)
    User->>KlerosCore: fundAppeal(disputeID, ...)
    KlerosCore->>DisputeKitBase: getCourtAndDisputeKitJumps(coreDisputeID, currentCourtID, parentCourtID, currentCourtJurorsForJump, currentRoundNbVotes)
    DisputeKitBase->>DisputeKitBase: Lookup courtIDToNextRoundSettings[currentCourtID]
    alt Next court/DK supported
        DisputeKitBase-->>KlerosCore: (newCourtID, newDisputeKitID, newRoundNbVotes, courtJump=false, disputeKitJump=false)
    else Not supported / incompatible
        DisputeKitBase-->>KlerosCore: (DISPUTE_KIT_CLASSIC, classicID, computedNbVotes, courtJump=?, disputeKitJump=true)
    end
    KlerosCore-->>User: proceed with resolved court/DK/votes/flags
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Audit: Contract Reviews 👀

Suggested reviewers

  • unknownunknown1
  • tractorss

Poem

🐰 I hopped through mappings, one court at a time,
Swapped globals for settings, each court gets a rhyme.
Draw now returns a subcourt in sight,
Jumps checked with care, fall back if not right.
A tiny rabbit cheers: neat logic, small bite! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Increased Court and DK jump logic flexibility" accurately reflects the main objective of the changeset. The PR's primary focus is refactoring the court and dispute kit jump logic from a hardcoded _jumpDisputeKitID approach to a more flexible system with per-court configuration via the new NextRoundSettings struct and changeNextRoundSettings governance function. The title captures this shift toward flexibility and configurability while remaining specific to the affected domains (court and dispute kit jumps). The title is clear enough that a teammate reviewing the pull request history would understand the primary change involves improvements to how courts and dispute kit jumps are handled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/next-round-settings-in-dk

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c40c12c and 9ea9e98.

📒 Files selected for processing (9)
  • contracts/hardhat.config.ts (1 hunks)
  • contracts/src/arbitration/KlerosCore.sol (4 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (6 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol (1 hunks)
  • contracts/src/arbitration/interfaces/IDisputeKit.sol (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests
🔇 Additional comments (15)
contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (1)

53-54: LGTM! Initializer signature updated consistently.

The removal of the _jumpDisputeKitID parameter aligns with the PR's shift to per-court next-round settings, and the base initializer call is correctly updated.

contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol (1)

47-49: LGTM! Consistent initializer update.

The parameter removal and updated base initializer call are consistent with the PR's architectural changes.

contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol (1)

29-30: LGTM! Initializer signature simplified.

Consistent with the removal of global jump settings across all dispute kit implementations.

contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol (1)

63-64: LGTM! Initializer updated consistently.

The signature change matches the pattern across all dispute kit implementations in this PR.

contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1)

82-83: LGTM! Initializer signature updated.

Consistent with the initialization changes across all dispute kit variants.

contracts/src/arbitration/KlerosCore.sol (3)

788-793: Verify unused return values are intentional.

The call to _getCourtAndDisputeKitJumps ignores newRoundNbVotes (line 788) and disputeKitJump (line 788) with underscores. While courtJump is used on line 794, confirm that disputeKitJump doesn't need to be emitted or tracked here. The DisputeKitJump event is emitted later at line 812, but only conditionally when the dispute kit actually changes.


1089-1094: LGTM! Return values properly utilized.

The function correctly unpacks all 5 return values from _getCourtAndDisputeKitJumps and uses nbVotesAfterAppeal and courtJump to compute the appeal cost. The ignored values (newCourtID and disputeKitJump) are appropriately not needed for cost calculation.


1183-1213: LGTM! Public getter provides transparency.

The new public getCourtAndDisputeKitJumps function appropriately exposes the jump logic for external callers and front-ends, enabling better visibility into dispute progression.

contracts/hardhat.config.ts (1)

35-35: Verify contract size remains under 24KB limit through proper build compilation.

The review comment's concern is valid—24.576 KB is the contract size limit on Ethereum—and the hardhat config confirms optimizer runs are "Constrained by the size of the KlerosCore contract."

Verification could not be completed in sandbox (compilation failed), but code analysis shows the PR changes are optimizations rather than bloat:

  • Removed isDisputeKitJumping() function (bytecode savings)
  • Added getCourtAndDisputeKitJumps() function (bytecode cost)
  • Removed external call to disputeKits[].getNbVotesAfterAppeal() and inlined the logic (further savings)

The net bytecode impact likely favors the changes. However, you should verify this locally by compiling and checking the deployed bytecode size before merging to confirm the contract remains compliant with the 24KB limit.

contracts/src/arbitration/interfaces/IDisputeKit.sol (2)

54-58: LGTM: Enhanced draw function signature.

The additional fromSubcourtID return value enables tracking which subcourt a juror was drawn from, which appears necessary for the new per-court settings logic.


127-154: Well-designed unified jump determination function.

This function consolidates the previously separate jump-related helpers (getJumpDisputeKitID, earlyCourtJump, getNbVotesAfterAppeal) into a single, comprehensive interface that returns all necessary jump information in one call. The documentation clearly states that compatibility validation is the Core's responsibility.

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (4)

61-68: Well-structured settings with fine-grained control.

The NextRoundSettings struct provides comprehensive per-court configuration with clear semantics. The enabled flag allows toggling settings without data loss, and the separate earlyDisputeKitJump and earlyCourtJump flags enable nuanced control over jump behavior.


631-670: Well-designed jump logic with appropriate fallbacks.

The implementation correctly handles multiple scenarios:

  1. Uses per-court settings when enabled
  2. Falls back to default behavior (vote doubling, parent court on jump, DISPUTE_KIT_CLASSIC) when settings are absent or zero
  3. Combines early jump flags with threshold-based jump detection (line 661-663), allowing jumps to occur via either mechanism

The logic flow ensures that even with partial settings, the function returns valid values.


433-434: No issues found — KlerosCore signature is correct.

KlerosCore.getCourtAndDisputeKitJumps at line 1190 accepts a single uint256 _disputeID parameter and returns five values: uint96 newCourtID, uint256 newDisputeKitID, uint256 newRoundNbVotes, bool courtJump, and bool disputeKitJump. The call in DisputeKitClassicBase.sol:433-434 correctly invokes this function with _coreDisputeID and destructures the fifth return value (isDisputeKitJumping) as expected.


161-169: Verify operational setup and document migration path for per-court dispute kit settings.

The architectural change from global _jumpDisputeKitID to per-court courtIDToNextRoundSettings introduces an operational concern. Verification confirms:

  1. No automatic initialization: The populateCourts script and deployment process do not call changeNextRoundSettings. Per-court settings must be manually configured via governance.

  2. Default behavior: Courts fall back to DISPUTE_KIT_CLASSIC until explicitly configured (line 668), which may be acceptable but is undocumented.

  3. Missing migration documentation: No deployment guide or migration script shows how to initialize settings for existing or newly deployed courts.

Recommended actions:

  • Document the expected post-deployment/upgrade process for initializing per-court settings
  • Consider automating this in populateCourts or provide a dedicated migration task
  • Ensure governance has clear procedures for configuring settings per court
  • Add safeguards or validation to prevent courts from operating in unconfigured state unintentionally

Comment on lines +196 to 204
/// @notice Changes the settings for the next round.
/// @param _currentCourtID The ID of the current court.
/// @param _nextRoundSettings The settings for the next round.
function changeNextRoundSettings(
uint96 _currentCourtID,
NextRoundSettings memory _nextRoundSettings
) external onlyByOwner {
courtIDToNextRoundSettings[_currentCourtID] = _nextRoundSettings;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add validation and event emission to governance function.

The function accepts settings without validation, which could allow governance to configure invalid court IDs, dispute kit IDs, or incompatible combinations. While Line 128 in the interface notes that compatibility checking is Core's responsibility, basic validation here would prevent governance errors.

Additionally, the function should emit an event to improve observability and enable off-chain monitoring of configuration changes.

Consider adding validation and an event:

+    event NextRoundSettingsChanged(uint96 indexed courtID, NextRoundSettings settings);
+
     function changeNextRoundSettings(
         uint96 _currentCourtID,
         NextRoundSettings memory _nextRoundSettings
     ) external onlyByOwner {
+        // Basic validation
+        if (_nextRoundSettings.enabled) {
+            if (_nextRoundSettings.jumpCourtID != 0) {
+                require(_nextRoundSettings.jumpCourtID < core.getNumberOfCourts(), "Invalid court ID");
+            }
+            if (_nextRoundSettings.jumpDisputeKitID != 0) {
+                require(_nextRoundSettings.jumpDisputeKitID < core.getNumberOfDisputeKits(), "Invalid DK ID");
+            }
+        }
         courtIDToNextRoundSettings[_currentCourtID] = _nextRoundSettings;
+        emit NextRoundSettingsChanged(_currentCourtID, _nextRoundSettings);
     }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 1259 to 1275
uint256 disputeKitID = _round.disputeKitID;
(
uint96 newCourtID,
uint256 newDisputeKitID,
uint256 newRoundNbVotes,
bool courtJump,
bool disputeKitJump
) = disputeKits[disputeKitID].getCourtAndDisputeKitJumps(
_disputeID,
_dispute.courtID,
_court.parent,
_court.jurorsForCourtJump,
_round.nbVotes
);

// Ensure compatibility between the next round's court and dispute kit.
if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID] || newDisputeKitID == NULL_DISPUTE_KIT) {
// Fall back to `DisputeKitClassic` which is always supported.
newDisputeKitID = DISPUTE_KIT_CLASSIC;
disputeKitJump = (newDisputeKitID != disputeKitID);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Verify newRoundNbVotes consistency after dispute kit fallback.

When the compatibility check (lines 1275-1278) falls back to DISPUTE_KIT_CLASSIC because the new court doesn't support the originally proposed dispute kit, the newRoundNbVotes value is not recalculated. This value was computed by the original dispute kit's getCourtAndDisputeKitJumps implementation, which might use different logic than what DISPUTE_KIT_CLASSIC would compute.

Confirm whether:

  1. The number of votes for a round is standardized and doesn't depend on the specific dispute kit implementation, OR
  2. The newRoundNbVotes should be recalculated by calling getCourtAndDisputeKitJumps again on the DISPUTE_KIT_CLASSIC instance after the fallback

Consider this scenario:

// Original DK (e.g., specialized kit) returns:
// newDisputeKitID = 5 (not supported by new court)
// newRoundNbVotes = 100 (calculated by specialized kit's logic)

// After fallback:
// newDisputeKitID = DISPUTE_KIT_CLASSIC (forced)
// newRoundNbVotes = 100 (still from specialized kit's logic)
// But DISPUTE_KIT_CLASSIC might compute it as 50 with its own logic

If this mismatch is intentional and safe, please document why. Otherwise, consider recalculating:

 // Ensure compatibility between the next round's court and dispute kit.
 if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID] || newDisputeKitID == NULL_DISPUTE_KIT) {
     // Fall back to `DisputeKitClassic` which is always supported.
     newDisputeKitID = DISPUTE_KIT_CLASSIC;
     disputeKitJump = (newDisputeKitID != disputeKitID);
+    // Recalculate votes with the fallback dispute kit
+    (, , newRoundNbVotes, , ) = disputeKits[DISPUTE_KIT_CLASSIC].getCourtAndDisputeKitJumps(
+        _disputeID,
+        _dispute.courtID,
+        _court.parent,
+        _court.jurorsForCourtJump,
+        _round.nbVotes
+    );
 }
🤖 Prompt for AI Agents
In contracts/src/arbitration/KlerosCore.sol around lines 1259 to 1280, after
falling back to DISPUTE_KIT_CLASSIC you must ensure newRoundNbVotes is
consistent with the chosen dispute kit: either (A) if the number of votes is
independent of dispute kit, add a clear comment documenting that fact and why
specialized kit values are safe to reuse; or (B) if vote count depends on the
dispute kit, recompute newRoundNbVotes by calling getCourtAndDisputeKitJumps
again on the DISPUTE_KIT_CLASSIC instance with the same parameters (passing
_disputeID, _dispute.courtID, _court.parent, _court.jurorsForCourtJump,
_round.nbVotes), and replace the previous newRoundNbVotes with that returned
value, also update disputeKitJump accordingly.

@jaybuidl jaybuidl force-pushed the feat/next-round-settings-in-dk branch from 9ea9e98 to fac9901 Compare October 21, 2025 18:24
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
16.7% Duplication on New Code (required ≤ 10%)

See analysis details on SonarQube Cloud

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/src/arbitration/KlerosCore.sol (1)

788-806: Use DK-computed vote count in appeal() to align with appealCost() estimation.

The inconsistency is confirmed. appealCost() (lines 1089, 1102, 1106) uses the dispute kit's computed nbVotesAfterAppeal, while appeal() (line 803) ignores the DK-returned newRoundNbVotes and instead calculates extraRound.nbVotes = msg.value / court.feeForJuror. This breaks the dispute kit abstraction—if the DK applies custom vote logic (thresholds, multipliers, rounding), the cost estimate and actual allocation diverge, potentially allowing overpayment to inflate vote counts beyond what the DK computed.

Recommended fix:

-        (uint96 newCourtID, uint256 newDisputeKitID, , bool courtJump, ) = _getCourtAndDisputeKitJumps(
+        (uint96 newCourtID, uint256 newDisputeKitID, uint256 newRoundNbVotes, bool courtJump, ) = _getCourtAndDisputeKitJumps(
             dispute,
             round,
             courts[dispute.courtID],
             _disputeID
         );
         // ...
         Court storage court = courts[newCourtID];
-        extraRound.nbVotes = msg.value / court.feeForJuror;
+        extraRound.nbVotes = newRoundNbVotes;
+        uint256 requiredFee = court.feeForJuror * newRoundNbVotes;
+        if (msg.value < requiredFee) revert AppealFeesNotEnough();
♻️ Duplicate comments (2)
contracts/src/arbitration/KlerosCore.sol (1)

1269-1274: Verify newRoundNbVotes consistency after dispute kit fallback.

When the compatibility check (lines 1270-1274) falls back to DISPUTE_KIT_CLASSIC because the new court doesn't support the originally proposed dispute kit, the newRoundNbVotes value is not recalculated. This value was computed by the original dispute kit's getCourtAndDisputeKitJumps implementation, which might use different logic than what DISPUTE_KIT_CLASSIC would compute.

Scenario:

// Original DK (e.g., specialized kit) returns:
// newDisputeKitID = 5 (not supported by new court)
// newRoundNbVotes = 100 (calculated by specialized kit's logic)

// After fallback:
// newDisputeKitID = DISPUTE_KIT_CLASSIC (forced)
// newRoundNbVotes = 100 (still from specialized kit's logic)
// But DISPUTE_KIT_CLASSIC might compute it as 50 with its own logic

Based on learnings from past review comments, this issue was previously identified. Confirm whether:

  1. The number of votes for a round is standardized and doesn't depend on the specific dispute kit implementation, OR
  2. The newRoundNbVotes should be recalculated by calling getCourtAndDisputeKitJumps again on the DISPUTE_KIT_CLASSIC instance after the fallback

If recalculation is needed:

 // Ensure compatibility between the next round's court and dispute kit.
 if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID] || newDisputeKitID == NULL_DISPUTE_KIT) {
     // Fall back to `DisputeKitClassic` which is always supported.
     newDisputeKitID = DISPUTE_KIT_CLASSIC;
     disputeKitJump = (newDisputeKitID != disputeKitID);
+    // Recalculate votes with the fallback dispute kit
+    (, , newRoundNbVotes, , ) = disputeKits[DISPUTE_KIT_CLASSIC].getCourtAndDisputeKitJumps(
+        _disputeID,
+        _dispute.courtID,
+        _court.parent,
+        _court.jurorsForCourtJump,
+        _round.nbVotes
+    );
 }
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

196-204: Validation and event emission still needed (echoing past review).

As noted in the previous review, this governance function should:

  1. Validate that court IDs and dispute kit IDs exist (at least basic bounds checking)
  2. Emit an event for off-chain monitoring and transparency

The past review comment provided a concrete suggestion with validation and an event. While the interface notes that Core handles compatibility checking (Line 128 in IDisputeKit), basic validation here prevents governance configuration errors.

Based on learnings (past review comments).

🧹 Nitpick comments (2)
contracts/deploy/00-home-chain-arbitration-mainnet.ts (1)

144-144: Address the TODO comment in the context of this PR.

The TODO comment asks about jumping to a Shutter DK instead of Classic. Since this PR introduces flexible per-court jump configuration via NextRoundSettings (see DisputeKitClassicBase.courtIDToNextRoundSettings), this is the ideal time to resolve this question. The default behavior can now be configured per-court after deployment using changeNextRoundSettings, but clarifying the intended default during initialization would improve code clarity.

Consider either:

  1. Removing the TODO if the per-court settings make this flexible enough
  2. Setting an explicit jumpDisputeKitID in the NextRoundSettings for courts using DisputeKitGatedShutter

Would you like me to search the codebase for how other dispute kits configure their jump targets?

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

631-670: Consider adding inline comments to clarify the decision flow.

The implementation correctly handles the complex interdependencies between nbVotes, courtJump, newCourtID, and newDisputeKitID. However, the logic flow has several non-obvious aspects:

  1. Line 658: The condition if (nextRoundSettings.nbVotes == 0) applies the default doubling formula even when enabled=true, which is correct but might be unexpected.

  2. Line 662: The condition if (!courtJump) means "if not explicitly set to true by earlyCourtJump", allowing the threshold check to proceed. This subtle override logic could use a comment.

  3. Lines 664-666: The newCourtID determination depends on the computed courtJump value, creating a dependency chain: newRoundNbVotes → threshold check → courtJumpnewCourtID selection.

Consider adding inline comments like:

+        // Use settings if configured, otherwise apply defaults
         if (nextRoundSettings.nbVotes == 0) {
+            // Default: double the votes and add 1
             newRoundNbVotes = (_currentRoundNbVotes * 2) + 1;
         }
         if (!courtJump) {
+            // Check threshold-based jump if not explicitly requested via earlyCourtJump
             courtJump = (newRoundNbVotes >= _currentCourtJurorsForJump);
         }
         if (newCourtID == 0) {
+            // Jump to parent court if threshold exceeded, otherwise stay in current
             newCourtID = courtJump ? _parentCourtID : _currentCourtID;
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ea9e98 and 973f572.

📒 Files selected for processing (14)
  • contracts/deploy/00-home-chain-arbitration-mainnet.ts (2 hunks)
  • contracts/deploy/00-home-chain-arbitration-university.ts (1 hunks)
  • contracts/deploy/00-home-chain-arbitration.ts (4 hunks)
  • contracts/hardhat.config.ts (1 hunks)
  • contracts/src/arbitration/KlerosCore.sol (4 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (6 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol (1 hunks)
  • contracts/src/arbitration/interfaces/IDisputeKit.sol (2 hunks)
  • contracts/test/arbitration/helpers/dispute-kit-gated-common.ts (1 hunks)
  • contracts/test/arbitration/helpers/dispute-kit-shutter-common.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • contracts/src/arbitration/dispute-kits/DisputeKitGated.sol
  • contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol
  • contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol
  • contracts/hardhat.config.ts
🧰 Additional context used
🧬 Code graph analysis (1)
contracts/deploy/00-home-chain-arbitration-mainnet.ts (2)
contracts/deploy/utils/deployUpgradable.ts (1)
  • deployUpgradable (37-89)
contracts/deployments/utils.ts (1)
  • deployments (3-16)
🔇 Additional comments (18)
contracts/deploy/00-home-chain-arbitration.ts (4)

40-40: LGTM! Deployment args correctly updated.

The removal of the fourth argument aligns with the updated initialize signature in DisputeKitClassic that no longer accepts _jumpDisputeKitID.


118-118: LGTM! Deployment args correctly updated.

The removal of the fourth argument aligns with the updated initialize signature in DisputeKitShutter.


127-127: LGTM! Deployment args correctly updated.

The removal of the fourth argument aligns with the updated initialize signature in DisputeKitGated.


136-136: Address the TODO comment regarding DK jump behavior.

The TODO suggests considering a jump to a Shutter DK instead of a Classic one. With the new per-court NextRoundSettings approach, this configuration should now be handled via changeNextRoundSettings rather than at initialization time. Consider whether this TODO is still relevant or should be updated/removed.

contracts/deploy/00-home-chain-arbitration-university.ts (1)

37-37: LGTM! Deployment args correctly updated.

The removal of the fourth argument aligns with the updated initialize signature for DisputeKitClassic.

contracts/test/arbitration/helpers/dispute-kit-gated-common.ts (1)

183-183: LGTM! Test setup correctly updated.

The removal of the fourth argument aligns with the updated dispute kit initialization signatures.

contracts/test/arbitration/helpers/dispute-kit-shutter-common.ts (1)

249-249: LGTM! Test setup correctly updated.

The removal of the fourth argument aligns with the updated initialize signature for DisputeKitGatedShutter.

contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1)

82-84: LGTM! Initializer correctly refactored.

The removal of _jumpDisputeKitID parameter and the updated base initializer call align with the new per-court NextRoundSettings design, where jump behavior is configured per court rather than globally at initialization.

contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol (1)

29-30: LGTM! Initializer correctly refactored.

The removal of _jumpDisputeKitID parameter and the updated base initializer call align with the new per-court NextRoundSettings design.

contracts/src/arbitration/KlerosCore.sol (1)

1183-1213: LGTM! Public getter properly delegates to internal helper.

The new public getCourtAndDisputeKitJumps function correctly exposes the internal jump logic for external callers, maintaining consistent behavior with internal usage.

contracts/src/arbitration/interfaces/IDisputeKit.sol (2)

54-58: LGTM! Draw signature extended for subcourt tracking.

The additional fromSubcourtID return value enables KlerosCore to track which subcourt a juror was drawn from, supporting more granular stake management.


127-154: LGTM! Consolidated jump logic improves interface clarity.

The new getCourtAndDisputeKitJumps function consolidates the previously fragmented jump-related methods (earlyCourtJump, getNbVotesAfterAppeal, getJumpDisputeKitID) into a single, comprehensive interface. This reduces complexity and provides all jump-related information in one call.

contracts/deploy/00-home-chain-arbitration-mainnet.ts (2)

34-34: LGTM! Correct alignment with updated initializer signature.

The args array correctly reflects the removal of _jumpDisputeKitID parameter. Using ZeroAddress for core is appropriate here since KlerosCore hasn't been deployed yet; Line 92 updates it via changeCore.


128-128: LGTM! Args correctly updated for new initializer signatures.

Both DisputeKitShutter and DisputeKitGated args arrays correctly reflect the removal of _jumpDisputeKitID and properly use core.target since KlerosCore is already deployed at this point.

Also applies to: 136-136

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (4)

61-68: Well-designed struct for per-court configuration.

The NextRoundSettings struct provides comprehensive control over next-round behavior with clear field semantics. The separation of earlyDisputeKitJump and earlyCourtJump flags allows fine-grained control over when jumps occur relative to threshold conditions.


85-85: LGTM! Appropriate storage for per-court settings.

The public mapping allows transparent per-court configuration and correctly uses uint96 for court IDs, matching KlerosCore's convention.


161-169: LGTM! Initializer correctly updated to remove global jump dispute kit ID.

The removal of _jumpDisputeKitID aligns with the PR's shift to per-court NextRoundSettings. This change is correctly reflected in the deployment scripts (e.g., Line 34 of 00-home-chain-arbitration-mainnet.ts).


433-434: LGTM! Correct usage of the new API.

The code correctly adapts to the expanded getCourtAndDisputeKitJumps return signature, extracting only the needed isDisputeKitJumping flag while skipping irrelevant return values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Compatibility: ABI change 🗯 Smart contract ABI is changing. Package: Contracts Court smart contracts Type: Feature🗿

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant