Skip to content

Conversation

jaybuidl
Copy link
Member

@jaybuidl jaybuidl commented Aug 15, 2025

This PR also includes a few minor unrelated changes

  • Consolidation of the ALPHA_DIVISOR and ONE_BASIS_POINTS constants
  • A typo fix in a local variable
  • A comment fix

PR-Codex overview

This PR focuses on improving the handling of coherence calculations in the Kleros arbitration system. It introduces a new constant for basis points and refactors functions to enhance clarity and maintainability.

Detailed summary

  • Added ONE_BASIS_POINT constant in Constants.sol.
  • Renamed function getDegreeOfCoherence to getDegreeOfCoherenceReward.
  • Introduced new function getDegreeOfCoherencePenalty.
  • Updated references to ALPHA_DIVISOR to use ONE_BASIS_POINT.
  • Refactored coherence calculations in multiple contracts to use new functions and constants.
  • Adjusted test cases to reflect changes in coherence functions.

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

Summary by CodeRabbit

  • New Features

    • Rewards and penalties now use separate coherence metrics for clearer, fairer distributions.
    • Calculations standardized in basis points for more precise and consistent outcomes.
  • Refactor

    • Unified basis-point constant adopted across arbitration modules; legacy divisor removed.
    • Internal naming cleanups with no behavioral change.
  • Documentation

    • Updated references to reflect the new reward/penalty coherence model.
  • Tests

    • Test suite updated to cover the split coherence logic without changing expected behavior.

Copy link

netlify bot commented Aug 15, 2025

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

Name Link
🔨 Latest commit 1dbfedf
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-university/deploys/689e7d1577b27b000808bb5e

Copy link

netlify bot commented Aug 15, 2025

Deploy Preview for kleros-v2-testnet ready!

Name Link
🔨 Latest commit 1dbfedf
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet/deploys/689e7d15ff60420007db225c
😎 Deploy Preview https://deploy-preview-2090--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.

Copy link

netlify bot commented Aug 15, 2025

Deploy Preview for kleros-v2-neo ready!

Name Link
🔨 Latest commit 1dbfedf
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-neo/deploys/689e7d155e92c300088646f8
😎 Deploy Preview https://deploy-preview-2090--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.

Copy link
Contributor

coderabbitai bot commented Aug 15, 2025

Walkthrough

Migrates coherence calculations from ALPHA_DIVISOR to basis points via ONE_BASIS_POINT, splits single coherence into reward (PNK/fee) and penalty paths, updates core, university, and dispute kit logic and interfaces accordingly, removes legacy constants, and adjusts tests and minor naming. Public API changes occur in IDisputeKit and DisputeKitClassicBase.

Changes

Cohort / File(s) Summary
Coherence model migration (core)
contracts/src/arbitration/KlerosCoreBase.sol, contracts/src/arbitration/university/KlerosCoreUniversity.sol
Replace ALPHA_DIVISOR with ONE_BASIS_POINT; switch to split coherence (penalty vs reward); update penalty/reward formulas, clamping, event params, and internal helpers.
Dispute kit API and logic
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
Move ONE_BASIS_POINT import; remove getDegreeOfCoherence; add getDegreeOfCoherenceReward and getDegreeOfCoherencePenalty; introduce shared _getDegreeOfCoherence helper returning binary coherence.
Interface update
contracts/src/arbitration/interfaces/IDisputeKit.sol
Replace getDegreeOfCoherence with getDegreeOfCoherenceReward (returns pnkCoherence, feeCoherence); add getDegreeOfCoherencePenalty (returns pnkCoherence).
Shared constants
contracts/src/libraries/Constants.sol
Add ONE_BASIS_POINT = 10000.
Legacy constant removal
contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol
Remove public ALPHA_DIVISOR constant.
Tests update
contracts/test/foundry/KlerosCore.t.sol
Update tests to use new reward/penalty coherence getters; assert identical outcomes under basis-point model.
Minor cleanup
contracts/src/arbitration/SortitionModuleBase.sol
Rename local variable currenCourtID → currentCourtID; no functional change.

Sequence Diagram(s)

sequenceDiagram
  participant Core as KlerosCore/KlerosCoreUniversity
  participant DK as DisputeKit (Classic)
  participant Juror as Juror

  Core->>DK: getDegreeOfCoherencePenalty(disputeID, roundID, voteID, feePerJuror, pnkAtStake)
  DK-->>Core: pnkCoherence (0..10000)
  Core->>Core: penalty = pnkAtStake * (10000 - coherence) / 10000
  Core-->>Juror: Apply penalty

  Core->>DK: getDegreeOfCoherenceReward(disputeID, roundID, voteID, feePerJuror, pnkAtStake)
  DK-->>Core: (pnkCoherence, feeCoherence)
  Core->>Core: pnkReward = ..., feeReward = ... using coherence/10000
  Core-->>Juror: Distribute PNK and fees
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested labels

Type: Feature🗿, Package: Contracts, Compatibility: ABI change 🗯

Suggested reviewers

  • clesaege
  • alcercu

Poem

I thump my paw at basis points,
Ten-thousand steps to fairer joints.
Rewards and fines now split in two,
A tidy warren, bright and new.
Hop, hop—events aligned just right,
Coherent burrows through the night. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/multi-dimensional-coherence

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@jaybuidl jaybuidl linked an issue Aug 15, 2025 that may be closed by this pull request
Copy link

Copy link

netlify bot commented Aug 15, 2025

Deploy Preview for kleros-v2-testnet-devtools ready!

Name Link
🔨 Latest commit 1dbfedf
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet-devtools/deploys/689e7d15bea97c0008f18a60
😎 Deploy Preview https://deploy-preview-2090--kleros-v2-testnet-devtools.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.

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: 5

🔭 Outside diff range comments (1)
contracts/src/arbitration/university/KlerosCoreUniversity.sol (1)

795-801: Avoid .send and unchecked return when transferring ETH; use .call and bubble errors.

ETH sends to governor ignore failure. Prefer .call{value: ...}("") and handle the boolean result to avoid silent loss of funds when governor is a contract with a reverting fallback.

-            if (round.feeToken == NATIVE_CURRENCY) {
-                // The dispute fees were paid in ETH
-                payable(governor).send(round.totalFeesForJurors);
-            } else {
+            if (round.feeToken == NATIVE_CURRENCY) {
+                // The dispute fees were paid in ETH
+                (bool ok, ) = payable(governor).call{value: round.totalFeesForJurors}("");
+                if (!ok) revert TransferFailed();
+            } else {
@@
-                    if (round.feeToken == NATIVE_CURRENCY) {
-                        // The dispute fees were paid in ETH
-                        payable(governor).send(leftoverFeeReward);
-                    } else {
+                    if (round.feeToken == NATIVE_CURRENCY) {
+                        // The dispute fees were paid in ETH
+                        (bool ok, ) = payable(governor).call{value: leftoverFeeReward}("");
+                        if (!ok) revert TransferFailed();
+                    } else {

Also applies to: 875-881

🧹 Nitpick comments (9)
contracts/src/arbitration/interfaces/IDisputeKit.sol (2)

70-79: Doc clarity: explicitly call out BPS and units for both return values.

Minor doc nit to make units explicit and self-contained for integrators.

Apply this diff to tighten the comments:

-    /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
-    /// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.
+    /// @return pnkCoherence Degree of coherence in basis points (0..10_000) for the PNK reward path.
+    /// @return feeCoherence Degree of coherence in basis points (0..10_000) for the fee reward path.

80-94: Penalty doc return mixes “reward” wording; fix to avoid ambiguity.

The penalty path return is described as “for the dispute PNK reward,” which is misleading here.

-    /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
+    /// @return pnkCoherence Degree of coherence in basis points (0..10_000) used by the PNK penalty path.
contracts/src/libraries/Constants.sol (1)

23-25: BPS denominator looks good; add a clarifying inline comment.

Tiny readability nit: call out that 10_000 equals 100% to avoid occasional confusion between “bps” vs “percent”.

-// Units
-uint256 constant ONE_BASIS_POINT = 10000;
+// Units
+// Basis points denominator: 10_000 == 100% (1 bps == 0.01%)
+uint256 constant ONE_BASIS_POINT = 10_000;
contracts/test/foundry/KlerosCore.t.sol (2)

2315-2340: Tests exercise the new split-API correctly.

Assertions for both PNK and fee coherences on reward path plus penalty path are consistent with Classic DK’s binary coherence. LGTM.

If you want extra coverage for arithmetic/rounding and clamping, consider adding a DK or a fixture that yields partial coherence (e.g., 3333 bps) and assert rounding behavior for:

  • pnkLocked, pnkReward, feeReward
  • leftover reward distribution.

2425-2443: LGTM on “no coherence” branch.

Split-API assertions for the zero-coherence scenario are aligned with execution semantics and leftover distribution path.

Optionally, add a check that results never exceed ONE_BASIS_POINT to enforce clamping at the API boundary.

contracts/src/arbitration/university/KlerosCoreUniversity.sol (1)

821-847: Optional: extract a small helper to DRY coherence application.

You can mirror Core’s _applyCoherence(amount, coherenceBps) to reduce repeated divisions and improve readability.

Example:

function _applyCoherence(uint256 amount, uint256 coherenceBps) internal pure returns (uint256) {
    return (amount * coherenceBps) / ONE_BASIS_POINT;
}

Then:

  • pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, pnkCoherence)
  • pnkReward = _applyCoherence(_params.pnkPenaltiesInRound / _params.coherentCount, pnkCoherence)
  • feeReward = _applyCoherence(round.totalFeesForJurors / _params.coherentCount, feeCoherence)
contracts/src/arbitration/KlerosCoreBase.sol (2)

846-847: Rename local variable for clarity (unlock amount, not "locked")

pnkLocked actually holds the amount to unlock (the coherent portion). Renaming improves readability and prevents confusion with “locked” semantics.

Apply this diff:

-        uint256 pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, pnkCoherence);
+        uint256 pnkToUnlock = _applyCoherence(round.pnkAtStakePerJuror, pnkCoherence);
 
-        // Release the rest of the PNKs of the juror for this round.
-        sortitionModule.unlockStake(account, pnkLocked);
+        // Release the coherent portion of the juror's locked PNK for this round.
+        sortitionModule.unlockStake(account, pnkToUnlock);

862-866: Event emits PNK coherence; fee coherence omission is acceptable

Given the existing TokenAndETHShift schema, emitting only pnkCoherence is consistent. If consumer tooling needs feeCoherence, consider a new event or indexed field in a follow-up.

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

542-556: Docstring mismatch: says “reward” in a penalty getter

The return description mentions reward, but this is the penalty path. Update the comment to avoid confusion for integrators.

Apply this diff:

-    /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
+    /// @return pnkCoherence The degree of coherence in basis points for the PNK penalty path.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3d211cc and 1dbfedf.

📒 Files selected for processing (8)
  • contracts/src/arbitration/KlerosCoreBase.sol (4 hunks)
  • contracts/src/arbitration/SortitionModuleBase.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (2 hunks)
  • contracts/src/arbitration/interfaces/IDisputeKit.sol (1 hunks)
  • contracts/src/arbitration/university/KlerosCoreUniversity.sol (7 hunks)
  • contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol (0 hunks)
  • contracts/src/libraries/Constants.sol (1 hunks)
  • contracts/test/foundry/KlerosCore.t.sol (2 hunks)
💤 Files with no reviewable changes (1)
  • contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-11-19T16:31:08.965Z
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:167-170
Timestamp: 2024-11-19T16:31:08.965Z
Learning: In the court hierarchy, child courts' `minStake` must be greater than or equal to their parent court's `minStake`.

Applied to files:

  • contracts/src/arbitration/SortitionModuleBase.sol
📚 Learning: 2024-11-19T16:31:08.965Z
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:167-170
Timestamp: 2024-11-19T16:31:08.965Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the `minStake` parameter is denominated in PNK, not ETH.

Applied to files:

  • contracts/src/arbitration/university/KlerosCoreUniversity.sol
⏰ 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-neo
  • GitHub Check: Redirect rules - kleros-v2-university
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-university
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: contracts-testing
  • GitHub Check: Pages changed - kleros-v2-university
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
🔇 Additional comments (15)
contracts/src/arbitration/SortitionModuleBase.sol (1)

347-355: Typo fix is correct; parent-walk logic remains intact.

currentCourtID rename is consistent across the loop, the _set call, and the parent lookup via core.courts. Behavior unchanged. LGTM.

contracts/src/arbitration/university/KlerosCoreUniversity.sol (2)

11-11: Importing ONE_BASIS_POINT centralizes units.

Good move to rely on shared constants instead of per-file divisors.


821-835: Reward/penalty split and clamping are implemented correctly.

  • Clamping to ONE_BASIS_POINT is defensive and prevents accidental overweight rewards.
  • Separate coherence for PNK and fees is applied consistently to pnkLocked, pnkReward, and feeReward.
  • Event payload now reflects PNK coherence, which matches the PNK path. LGTM.

Also applies to: 839-847, 860-864

contracts/src/arbitration/KlerosCoreBase.sol (9)

769-777: Good migration to penalty-specific coherence API

Switched to disputeKit.getDegreeOfCoherencePenalty with the extended signature. Passing both feePerJurorInRound and pnkAtStakePerJurorInRound aligns with the new interface and preserves extensibility across DKs.


778-781: Clamping coherence to ONE_BASIS_POINT is correct

Defensive cap avoids accidental over-1 basis-point values leaking from DKs. This prevents negative penalties and over-rewards.


784-784: Penalty formula matches basis-point semantics

Using (stake * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT keeps penalties proportional and consistent with reward-side coherence, with rounding handled symmetrically by the leftover path.


797-801: Event coherence value is consistent with the penalty path

Emitting the coherence (not the penalty) keeps the event payload semantically aligned with the reward-side event. This helps off-chain consumers interpret shifts uniformly.


829-836: Good split of reward coherences (PNK vs fees)

Using disputeKit.getDegreeOfCoherenceReward to obtain separate pnkCoherence and feeCoherence values future-proofs the design for multi-dimensional DKs.


838-844: Clamping both PNK and fee coherences is appropriate

The explicit guard ensures downstream math stays within expected bounds even if a DK misreports.


852-855: Reward computation matches the two-pass model and leftover handling

  • PNK reward is proportional to coherence over the per-capita penalty pool.
  • Fee reward is proportional to coherence over the per-capita fee pool.
    Leftovers are handled at the end of the second pass, avoiding rounding drift accumulation.

1065-1069: _applyCoherence migrated to basis points cleanly

Simple and explicit basis-point application improves clarity vs ALPHA_DIVISOR and centralizes the scaling factor through ONE_BASIS_POINT.


1076-1077: _calculatePnkAtStake uses ONE_BASIS_POINT as intended

Matches the new constant and keeps math consistent across the codebase.

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

9-9: Centralizing ONE_BASIS_POINT import is the right move

Explicit import from Constants.sol removes duplication and keeps the scale factor canonical.


531-541: Reward coherence getter implementation is sound

  • Returns identical values for PNK and fee coherence, which is correct for Classic DK.
  • Uses the shared _getDegreeOfCoherence helper to avoid duplication.

557-573: Coherence helper is correct and minimal

Binary coherence (0 or ONE_BASIS_POINT) when voted and either tied or matched winning choice matches Classic semantics. Keeps non-voters at 0.

@jaybuidl jaybuidl merged commit 96e48f8 into dev Aug 20, 2025
18 of 24 checks passed
@jaybuidl jaybuidl deleted the feat/multi-dimensional-coherence branch August 20, 2025 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Contracts: Multi-dimensional Degree of Coherence (future-proofing)
2 participants