Skip to content

Conversation

jaybuidl
Copy link
Member

@jaybuidl jaybuidl commented Aug 20, 2025

PR-Codex overview

This PR introduces a new function setStakeReward to manage juror rewards by staking PNK instead of transferring it directly. It also updates the logic for reward calculations and adjustments in related contracts.

Detailed summary

  • Added setStakeReward function in ISortitionModule to stake rewards.
  • Updated KlerosCoreBase and KlerosCoreUniversity to compute and stake rewards.
  • Adjusted test cases to reflect new reward logic.
  • Changed comments to clarify reward handling processes.

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

Summary by CodeRabbit

  • New Features

    • Juror PNK rewards can now be credited directly to jurors' stakes in their court, increasing future staking power; if staking isn't possible the reward is still paid out as tokens.
    • Existing fee rewards (ETH/ERC20) are unchanged.
  • Tests

    • Updated test expectations to reflect staking-based reward distribution and resulting balance shifts.
  • Changelog

    • Noted as a breaking change: default behavior now supports staking juror PNK rewards.

Copy link
Contributor

coderabbitai bot commented Aug 20, 2025

Walkthrough

Implements conditional auto-staking of juror PNK rewards via a new SortitionModule.setStakeReward API. KlerosCore reward execution now attempts to deposit PNK rewards into juror stakes and falls back to direct token transfer if staking fails. Interfaces, sortition implementations, core/university reward flow, tests, and CHANGELOG updated.

Changes

Cohort / File(s) Summary
Core reward flow
contracts/src/arbitration/KlerosCoreBase.sol, contracts/src/arbitration/university/KlerosCoreUniversity.sol
_executeRewards now computes pnkReward, transfers fee reward, then calls sortitionModule.setStakeReward(account, dispute.courtID, pnkReward). If it returns false, falls back to pinakion.safeTransfer. Accounting updates remain unchanged.
Sortition interface
contracts/src/arbitration/interfaces/ISortitionModule.sol
Adds setStakeReward(address _account, uint96 _courtID, uint256 _reward) external returns (bool success);.
Sortition base & university impl
contracts/src/arbitration/SortitionModuleBase.sol, contracts/src/arbitration/university/SortitionModuleUniversity.sol
Adds setStakeReward external onlyByCore: returns true for zero reward, false if juror has no current stake, otherwise applies deposit via _setStake. University adds setStake(...) external and internal _setStake(...) to update juror/court stakes and emit events.
Tests
contracts/test/foundry/KlerosCore.t.sol
Updates expected PNK balances to reflect staking path (two assertions updated).
Changelog
contracts/CHANGELOG.md
Adds Breaking entry: “Stake the juror's PNK rewards instead of transferring them out” (#2099).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Core as KlerosCore._executeRewards
  participant Sort as SortitionModule
  participant PNK as Pinakion Token

  Core->>PNK: Transfer fee reward (ETH/ERC20 path unchanged)
  Note over Core: compute pnkReward

  Core->>Sort: setStakeReward(account, courtID, pnkReward)
  alt succeeds (returns true)
    Note over Sort,Core: reward credited to juror stake (no transfer)
  else fails (returns false)
    Core->>PNK: safeTransfer(account, pnkReward)
    Note over Core: fallback direct PNK payout
  end

  Note over Core: update sumPnkRewardPaid / sumFeeRewardPaid (logged unchanged)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels

Type: Enhancement :sparkles:

Suggested reviewers

  • unknownunknown1
  • alcercu

Poem

A rabbit hops to ledger light,
Rewards take root instead of flight.
If soil accepts, my PNK will stay—
If not, I carry it away.
Tiny paws, big justice day. 🥕🐇

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.


📜 Recent 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 0cadf21 and 524116c.

📒 Files selected for processing (1)
  • contracts/CHANGELOG.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • contracts/CHANGELOG.md
⏰ 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). (15)
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Mend Security Check
  • GitHub Check: contracts-testing
  • GitHub Check: Analyze (javascript)
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/autostake-pnk-rewards

🪧 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 20, 2025 that may be closed by this pull request
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: 1

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

32-33: Add NatSpec to document new reward-staking API and its return semantics

The new function is clear, but please document:

  • When it returns false (e.g., juror not staked in that court, or other preconditions).
  • That it must not create a new stake path (only top-up existing court stake).
  • Whether phase constraints apply (see my comment on SortitionModuleBase).

This helps downstream implementers and keeps interface behavior unambiguous.


32-33: Optional: encode phase behavior in the interface comment

If you adopt phase gating in setStakeReward, please reflect that in the interface comments so callers (Core) understand that return false may simply mean “not Staking phase,” and should fallback to transfer.

Would you like me to update the interface NatSpec if we merge the phase gate?

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

309-318: Consider emitting a dedicated event for reward-based stake increases

Today, reward credits emit StakeSet only, making it hard to distinguish user-initiated staking from reward compounding in off-chain analytics. An optional, additive event (e.g., RewardStaked(address juror, uint96 courtID, uint256 reward)) helps indexers and dashboards.

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

858-862: Avoid external call when pnkReward is zero, and rely on phase-gated setStakeReward

Two small tweaks:

  • Skip calling sortitionModule when pnkReward == 0 to save gas.
  • If you accept gating setStakeReward to Staking phase (see SortitionModuleBase note), this code remains correct: it will fall back to transfer when false.

Diff within this hunk:

-        // Stake the PNK reward if possible, by-passes delayed stakes and other checks usually done by validateStake()
-        if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {
-            pinakion.safeTransfer(account, pnkReward);
-        }
+        // Stake the PNK reward if possible (phase-gated in SortitionModule); otherwise transfer.
+        if (pnkReward != 0) {
+            if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {
+                pinakion.safeTransfer(account, pnkReward);
+            }
+        }

If you don’t adopt the phase gate, please confirm you’re comfortable with sum-tree mutations during Generating/Drawing potentially affecting ongoing draws in other disputes.

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

850-857: Prefer a safe, unified fee payout instead of raw send()

University version still uses payable(account).send(feeReward) (unchecked boolean). Consider mirroring KlerosCoreBase’s _transferFeeToken pattern (SafeSend) to avoid silent failures and to standardize behavior across variants. If you want to keep University minimal, at least check the boolean and revert on failure.

Example minimal change:

-        if (round.feeToken == NATIVE_CURRENCY) {
-            // The dispute fees were paid in ETH
-            payable(account).send(feeReward);
-        } else {
-            // The dispute fees were paid in ERC20
-            round.feeToken.safeTransfer(account, feeReward);
-        }
+        if (round.feeToken == NATIVE_CURRENCY) {
+            require(payable(account).send(feeReward), "ETH fee payout failed");
+        } else {
+            round.feeToken.safeTransfer(account, feeReward);
+        }

858-862: Skip SortitionModule call for zero reward and rely on phase-gate behavior

Same gas/tidiness nit as base contract: avoid calling setStakeReward when pnkReward == 0; if setStakeReward is gated to Staking phase, fallback to transfer preserves behavior during Drawing/Generating.

-        if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {
-            pinakion.safeTransfer(account, pnkReward);
-        }
+        if (pnkReward != 0) {
+            if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {
+                pinakion.safeTransfer(account, pnkReward);
+            }
+        }
contracts/test/foundry/KlerosCore.t.sol (1)

2400-2403: Fix comments to reflect the new autostake behavior

The assertions are correct, but the inline comments contradict them:

  • Core balance comment says “Was 21500. 1000 was transferred to staker2” — here 1000 was autostaked (into staker2’s stake via core custody), not transferred to wallet.
  • staker2 comment says “thus -19k from the default” — the wallet is down by 20k (stake), the 1k reward is staked, not in wallet.

Proposed diff (comments only):

-        assertEq(pinakion.balanceOf(address(core)), 21500, "Wrong token balance of the core"); // Was 21500. 1000 was transferred to staker2
+        assertEq(pinakion.balanceOf(address(core)), 21500, "Wrong token balance of the core"); // 1000 PNK reward was autostaked (held by core)
...
-        assertEq(pinakion.balanceOf(staker2), 999999999999980000, "Wrong token balance of staker2"); // 20k stake and 1k added as a reward, thus -19k from the default
+        assertEq(pinakion.balanceOf(staker2), 999999999999980000, "Wrong token balance of staker2"); // 20k deposited as stake; 1k reward autostaked (not in wallet)
contracts/src/arbitration/university/SortitionModuleUniversity.sol (2)

220-226: _setStake entry point looks good; note minor gas/readability tweaks.

No functional issues spotted. Optional micro-tweaks you may consider:

  • Make the deposit/withdraw branches explicit: if (_pnkDeposit > 0) { ... } else if (_pnkWithdrawal > 0) { ... } to skip the no-op subtraction when both are zero.
  • In the cleanup loop that walks courtIDs in reverse, use unchecked decrement to save gas.
  • In the ancestor update, consider applying a single delta per court (±(new - current)) instead of two consecutive updates to reduce SSTOREs.

If helpful, I can draft a focused gas-optimized variant of the loop/update block.


206-218: setStakeReward behavior confirmed; optional O(1) lookup refactor and event emission recommended

  • Verified that in SortitionModuleUniversity.sol (lines 206–218) setStakeReward(address,uint96,uint256) is declared as
    external override onlyByCore returns (bool success) and uses the intended early-return logic:
    ● returns true when _reward == 0
    ● returns false when the juror’s current stake is zero, allowing the caller to fallback to a direct transfer
  • Checked KlerosCoreUniversity.sol (line 859) and KlerosCoreBase.sol (line 859) and confirmed that both core implementations handle a false return by calling pinakion.safeTransfer(account, pnkReward) as a fallback—ensuring no funds are lost when auto-staking isn’t possible
  • The method signature and caller expectations align correctly; no breaking changes detected

Optional improvements to consider:

  • Replace the O(n) scan in _stakeOf(_account,_courtID) with a direct storage lookup (e.g. jurors[_account].stakesByCourtID[_courtID]) to reduce gas in hot reward loops
  • Emit a dedicated RewardAutoStaked(address indexed account, uint96 indexed courtID, uint256 reward, uint256 newStake) event immediately after _setStake for easier off-chain indexing and auditing
📜 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 9895c7c and 0cadf21.

📒 Files selected for processing (6)
  • contracts/src/arbitration/KlerosCoreBase.sol (1 hunks)
  • contracts/src/arbitration/SortitionModuleBase.sol (1 hunks)
  • contracts/src/arbitration/interfaces/ISortitionModule.sol (1 hunks)
  • contracts/src/arbitration/university/KlerosCoreUniversity.sol (1 hunks)
  • contracts/src/arbitration/university/SortitionModuleUniversity.sol (1 hunks)
  • contracts/test/foundry/KlerosCore.t.sol (1 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). (2)
  • GitHub Check: contracts-testing
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
contracts/src/arbitration/KlerosCoreBase.sol (2)

849-854: Micro: reuse helper to compute rewards (already done) – looks good

The switch to _applyCoherence improves readability and reduces duplication. No action needed.


855-857: Uniform fee transfer helper: good call

Using _transferFeeToken unifies ETH/ERC20 payout logic and inherits SafeSend behavior. Nice.

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

843-848: LGTM on reward computation

The reward math mirrors the base contract and maintains sumPnkRewardPaid/sumFeeRewardPaid accounting. Good.

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

193-195: Good extraction: single source of truth for stake mutations via _setStake.

Routing setStake through the internal helper removes duplication and ensures the rewards path shares identical accounting side-effects and events. LGTM.

Copy link

netlify bot commented Aug 20, 2025

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

Name Link
🔨 Latest commit 524116c
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet-devtools/deploys/68acb75dadceef0008162055
😎 Deploy Preview https://deploy-preview-2099--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

netlify bot commented Aug 20, 2025

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

Name Link
🔨 Latest commit 524116c
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-university/deploys/68acb75d1b95a20007fbfbe6

Copy link

netlify bot commented Aug 20, 2025

Deploy Preview for kleros-v2-neo ready!

Name Link
🔨 Latest commit 524116c
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-neo/deploys/68acb75d9518720008c0e7f9
😎 Deploy Preview https://deploy-preview-2099--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

netlify bot commented Aug 20, 2025

Deploy Preview for kleros-v2-testnet ready!

Name Link
🔨 Latest commit 524116c
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet/deploys/68acb75dae0f5f00084a76c2
😎 Deploy Preview https://deploy-preview-2099--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.

coderabbitai[bot]
coderabbitai bot previously approved these changes Aug 21, 2025
Copy link

@jaybuidl jaybuidl merged commit 9618a6f into dev Aug 25, 2025
20 of 24 checks passed
@jaybuidl jaybuidl deleted the feat/autostake-pnk-rewards branch August 25, 2025 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PNK Rewards Auto-Staking

1 participant