Skip to content

Conversation

@jaybuidl
Copy link
Member

@jaybuidl jaybuidl commented Oct 25, 2025

PR-Codex overview

This PR focuses on enhancing the draw functionality across various DisputeKit implementations in the Kleros arbitration system. It adds a new parameter for the number of votes in the drawing process and ensures that this parameter is used consistently in related checks and logic.

Detailed summary

  • Updated draw function signatures in multiple contracts to include _roundNbVotes.
  • Adjusted calls to draw to pass the new _roundNbVotes parameter.
  • Modified _postDrawCheck to incorporate _roundNbVotes in checks for juror eligibility.
  • Introduced a new dispute kit, DisputeKitGatedArgentinaConsumerProtection, implementing specific logic for drawing jurors based on token ownership.
  • Added tests to verify the drawing logic for the new dispute kit, ensuring proper behavior under various scenarios.

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

Summary by CodeRabbit

  • New Features

    • Argentina consumer-protection dispute module with token-gated juror participation and tracking of consumer-protection juror draws.
  • Refactor

    • Dispute drawing now passes upcoming round vote counts into dispute-kit draws to align selection and validation across rounds.
  • Tests

    • New comprehensive tests covering token-gated drawing, mixed-token scenarios, round-specific requirements, and draw-state mapping.
For accredited Argentinian consumer protection lawyers
@netlify
Copy link

netlify bot commented Oct 25, 2025

Deploy Preview for kleros-v2-neo ready!

Name Link
🔨 Latest commit 32fe70a
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-neo/deploys/68ff886e520d5f00085a5af3
😎 Deploy Preview https://deploy-preview-2189--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 25, 2025

Deploy Preview for kleros-v2-testnet ready!

Name Link
🔨 Latest commit 32fe70a
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet/deploys/68ff886ea2c54d00085de6d4
😎 Deploy Preview https://deploy-preview-2189--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 25, 2025

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

Name Link
🔨 Latest commit 32fe70a
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet-devtools/deploys/68ff886e748042000833c920
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 25, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a _roundNbVotes parameter to the dispute-kit draw API and propagates it from core draw call sites; updates disputed-kit _postDrawCheck signatures and implementations; introduces a new token‑gated dispute kit (DisputeKitGatedArgentinaConsumerProtection) with drawing tests enforcing token-based juror requirements.

Changes

Cohort / File(s) Summary
Interface
contracts/src/arbitration/interfaces/IDisputeKit.sol
draw signature changed to draw(uint256 _coreDisputeID, uint256 _nonce, uint256 _roundNbVotes) and NatSpec updated.
Core Callsites
contracts/src/arbitration/KlerosCore.sol, contracts/src/arbitration/university/KlerosCoreUniversity.sol
All disputeKit.draw(...) calls now pass round.nbVotes as the third argument.
Base Dispute Kit
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
draw visibility/signature changed to public virtual override accepting _roundNbVotes (unused in body); _postDrawCheck signature updated to accept _roundNbVotes and return bool.
New Gated DK
contracts/src/arbitration/dispute-kits/DisputeKitGatedArgentinaConsumerProtection.sol
New DK extending DisputeKitClassicBase: version constant, two accredited token addresses, draw override that records drawnConsumerProtectionLawyer per dispute/round, initializer, token update functions, UUPS auth, TokenNotSupported error, and token-holder checks during draws.
Gated / Variants
contracts/src/arbitration/dispute-kits/DisputeKitGated.sol, .../DisputeKitGatedShutter.sol
_postDrawCheck signatures extended to include _roundNbVotes and forwarded to super.
Sybil / Other DKs
contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol
_postDrawCheck signature extended to include _roundNbVotes, forwarded to base logic and used in PoH/validation checks.
Tests
contracts/test/foundry/DisputeKitGatedArgentinaConsumerProtection_Drawing.t.sol, contracts/test/foundry/KlerosCore_Appeals.t.sol
New drawing tests for the Argentina gated DK; test callsites updated to pass nbVotes to draw.

Sequence Diagram(s)

sequenceDiagram participant KC as KlerosCore / KlerosCoreUniversity participant DK as IDisputeKit / DisputeKitClassicBase participant DKG as DisputeKitGatedArgentinaConsumerProtection rect rgb(230,240,255) Note over KC,DK: Core passes round.nbVotes into draw KC->>DK: draw(_disputeID, startIndex, round.nbVotes) end rect rgb(245,250,245) Note over DK: Base draw selects juror and runs _postDrawCheck(..., _roundNbVotes) DK->>DK: select juror -> _postDrawCheck(..., _roundNbVotes) DK-->>KC: (drawnAddress, fromSubcourtID) end rect rgb(245,235,245) Note over DKG: Gated DK records consumer-protection draws KC->>DKG: draw(..., _roundNbVotes) DKG->>DKG: super.draw(...) => drawnAddress alt drawn holds consumer-protection token DKG->>DKG: drawnConsumerProtectionLawyer[localDispute][localRound] = true else DKG->>DKG: may trigger re-draw or clear marker if round complete end DKG-->>KC: (drawnAddress, fromSubcourtID) end 
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • New DisputeKitGatedArgentinaConsumerProtection: initializer/UUPS, token checks, mapping lifecycle and edge cases around marking/clearing drawnConsumerProtectionLawyer.
    • Consistent adoption of the new draw(..., _roundNbVotes) signature across DKs and tests.
    • _postDrawCheck signature changes and correct propagation of _roundNbVotes in overrides.

Possibly related PRs

Suggested labels

Compatibility: ABI change 🗯

Suggested reviewers

  • unknownunknown1
  • alcercu

Poem

🐰 I nudge the ledger, paw in code,
Votes lined up down the juror road,
Tokens guard a lawyer's place,
One drawn mark lights a round's small space,
A rabbit hops — the draw is owed. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "New dispute kit gated for Argentinian consumer protection lawyers" accurately describes a significant and new feature introduced in this PR—the addition of DisputeKitGatedArgentinaConsumerProtection contract with token-based gating logic. However, the PR encompasses a broader scope of changes beyond the new dispute kit. Specifically, the PR refactors the draw function signature across multiple core files (KlerosCore.sol, KlerosCoreUniversity.sol, IDisputeKit.sol, DisputeKitClassicBase.sol, and several other dispute kit implementations) to introduce a new _roundNbVotes parameter. According to the PR objectives, both changes—updating the draw function signature and adding the new gated dispute kit—are equally important to the PR's intent. The title addresses one substantial aspect of the change but does not capture the pervasive refactoring that affects many core components and implementations.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f64aba and 32fe70a.

📒 Files selected for processing (2)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedArgentinaConsumerProtection.sol (1 hunks)
  • contracts/test/foundry/DisputeKitGatedArgentinaConsumerProtection_Drawing.t.sol (1 hunks)

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

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/university/KlerosCoreUniversity.sol (1)

1061-1063: Guard against division by zero in convertEthToTokenAmount.

If a token is marked accepted but rateInEth==0, this will revert. Validate rate configured (non‑zero) before use or revert early.

 function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) { - return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth; + uint64 rate = currencyRates[_toToken].rateInEth; + if (rate == 0) revert TokenNotAccepted(); // or dedicated error + return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / rate; }
🧹 Nitpick comments (2)
contracts/src/arbitration/university/KlerosCoreUniversity.sol (1)

812-817: Avoid raw send; use a safe send helper consistently.

send(...) ignores failures; prefer SafeSend (as in KlerosCore) to prevent silent fund loss.

- payable(owner).send(round.totalFeesForJurors); + // use SafeSend.safeSend with wNative analogue or SafeERC20 for ERC20 path only

Also applies to: 868-873, 900-905

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

99-117: Slight gas/readability: cache round.

Avoid repeated dispute.rounds[localRoundID] lookups; store Round storage round = dispute.rounds[localRoundID].

- uint256 localRoundID = dispute.rounds.length - 1; + uint256 localRoundID = dispute.rounds.length - 1; + Round storage round = dispute.rounds[localRoundID]; @@ - if ( - dispute.rounds[localRoundID].votes.length == _roundNbVotes && + if ( + round.votes.length == _roundNbVotes && !drawnConsumerProtectionLawyer[localDisputeID][localRoundID] ) { @@ - dispute.rounds[localRoundID].votes.pop(); + round.votes.pop();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8536e6 and b6ca2ad.

📒 Files selected for processing (5)
  • contracts/src/arbitration/KlerosCore.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedArgentinaConsumerProtection.sol (1 hunks)
  • contracts/src/arbitration/interfaces/IDisputeKit.sol (1 hunks)
  • contracts/src/arbitration/university/KlerosCoreUniversity.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). (14)
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests
🔇 Additional comments (4)
contracts/src/arbitration/KlerosCore.sol (1)

756-760: Core passes nbVotes to DK.draw — OK.

Matches the new interface; loop semantics unchanged; continue on zero address still correct.

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

254-263: Base DK draw signature update — OK.

Visibility/public override and unused param pattern are correct; maintains behavior.

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

53-60: Verified — all DisputeKit implementations updated to 3-arg signature.

All DisputeKit implementations now use the new signature with _roundNbVotes:

  • DisputeKitGatedArgentinaConsumerProtection uses all three parameters
  • DisputeKitClassicBase accepts the parameter (marked unused with comment, valid pattern)
  • No legacy 2-arg implementations remain in codebase
contracts/src/arbitration/university/KlerosCoreUniversity.sol (1)

605-605: All DK implementations verified to use the correct 3‑arg draw signature.

The interface IDisputeKit.draw() expects (uint256 _coreDisputeID, uint256 _nonce, uint256 _roundNbVotes). Both DisputeKitClassicBase and DisputeKitGatedArgentinaConsumerProtection implement this correctly with 3 parameters. Other dispute kits inherit from DisputeKitClassicBase and thus maintain the same signature. The call at line 605 in KlerosCoreUniversity passes 3 arguments as required.

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 25, 2025
@jaybuidl jaybuidl self-assigned this Oct 25, 2025
@jaybuidl jaybuidl marked this pull request as ready for review October 25, 2025 01:48
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

🧹 Nitpick comments (1)
contracts/test/foundry/DisputeKitGatedArgentinaConsumerProtection_Drawing.t.sol (1)

154-168: Consider removing debug console.log statements.

The test includes several console.log statements that appear to be debugging artifacts. These should be removed before merging to production to keep test output clean.

- // Debug: Log the values being encoded - console.log("argentinaCourt:", argentinaCourt); - console.log("DEFAULT_NB_OF_JURORS:", DEFAULT_NB_OF_JURORS); - console.log("ARGENTINA_DK_ID:", ARGENTINA_DK_ID); - // Verify the arbitration cost is correct - use uint256 for all values bytes memory extraData = abi.encodePacked( uint256(argentinaCourt), uint256(DEFAULT_NB_OF_JURORS), uint256(ARGENTINA_DK_ID) ); - console.log("extraData length:", extraData.length); uint256 cost = core.arbitrationCost(extraData); - console.log("Actual cost:", cost); - console.log("Expected cost:", 0.03 ether * DEFAULT_NB_OF_JURORS); assertEq(cost, 0.03 ether * DEFAULT_NB_OF_JURORS, "Wrong arbitration cost");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6ca2ad and f5f3079.

📒 Files selected for processing (2)
  • contracts/test/foundry/DisputeKitGatedArgentinaConsumerProtection_Drawing.t.sol (1 hunks)
  • contracts/test/foundry/KlerosCore_Appeals.t.sol (4 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-neo
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: hardhat-tests
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (12)
contracts/test/foundry/KlerosCore_Appeals.t.sol (4)

345-345: LGTM! Correctly updated test to match new draw signature.

The test properly verifies that a dispute kit rejects draw calls after the dispute has jumped to another kit, now using the updated 3-parameter signature.


494-494: LGTM! Test update is consistent with new draw signature.


718-718: LGTM! Correctly updated for recurring DK jump test.


797-797: LGTM! Test updates complete and consistent.

All draw calls in the appeals test suite have been correctly updated to use the new 3-parameter signature with _roundNbVotes.

contracts/test/foundry/DisputeKitGatedArgentinaConsumerProtection_Drawing.t.sol (8)

47-130: LGTM! Well-structured test setup.

The setUp function comprehensively covers all necessary test scenarios:

  • Six test accounts representing different token ownership combinations
  • Proper dispute kit and court initialization
  • Correct token deployment and configuration
  • Adequate PNK distribution for staking

174-206: LGTM! Test correctly validates rejection of draws without consumer protection lawyers.

The test properly verifies that when only regular accredited lawyers (without consumer protection tokens) are staked, the drawing process cannot complete because it cannot satisfy the requirement of having at least one consumer protection lawyer per round.


209-244: LGTM! Test correctly validates successful drawing with consumer protection lawyers.


247-285: LGTM! Test correctly validates mixed lawyer scenario.

The test appropriately uses extra iterations (* 5) to handle potential retries when drawing from a mixed pool of regular and consumer protection lawyers.


288-329: LGTM! Test correctly validates jurors holding both token types.


332-363: LGTM! Test correctly validates rejection of jurors without tokens.


366-445: LGTM! Comprehensive test of multi-round consumer protection requirement.

The test correctly validates that each round independently satisfies the consumer protection lawyer requirement, including proper handling of appeals and round escalation (3 jurors → 7 jurors).


448-502: LGTM! Mapping test and helper function are well-implemented.

The test correctly validates the drawnConsumerProtectionLawyer mapping state transitions, and the helper function properly verifies the consumer protection lawyer requirement across multiple tests.

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 25, 2025
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

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/dispute-kits/DisputeKitGated.sol (1)

111-126: OOB/garbage read of tokenId (length check off by 32 bytes).

You read at add(_extraData, 0xA0) but only guard for < 160. Require ≥192 or read tokenId conditionally.

- // Need at least 160 bytes to safely read the parameters - if (_extraData.length < 160) return (address(0), false, 0); + // Need at least 160 bytes to read tokenGate/isERC1155; 192 if tokenId is present. + if (_extraData.length < 160) return (address(0), false, 0); assembly { // solium-disable-line security/no-inline-assembly - let packedTokenGateIsERC1155 := mload(add(_extraData, 0x80)) // 4th parameter at offset 128 - tokenId := mload(add(_extraData, 0xA0)) // 5th parameter at offset 160 (moved up) + let packedTokenGateIsERC1155 := mload(add(_extraData, 0x80)) // 4th parameter at offset 128 // Unpack address from lower 160 bits and bool from bit 160 tokenGate := and(packedTokenGateIsERC1155, 0xffffffffffffffffffffffffffffffffffffffff) isERC1155 := and(shr(160, packedTokenGateIsERC1155), 1) } + if (_extraData.length >= 192) { + assembly { tokenId := mload(add(_extraData, 0xA0)) } // 5th parameter at offset 160 + } else { + tokenId = 0; + }
♻️ Duplicate comments (3)
contracts/src/arbitration/dispute-kits/DisputeKitGatedArgentinaConsumerProtection.sol (3)

55-59: Validate token addresses on init (avoid ABI decode revert at runtime).

Reject zero/EOA tokens up-front.

 ) external initializer { __DisputeKitClassicBase_initialize(_owner, _core, _wNative); - accreditedLawyerToken = _accreditedLawyerToken; - accreditedConsumerProtectionLawyerToken = _accreditedConsumerProtectionLawyerToken; + if (_accreditedLawyerToken == address(0) || _accreditedLawyerToken.code.length == 0) + revert TokenNotSupported(_accreditedLawyerToken); + if (_accreditedConsumerProtectionLawyerToken == address(0) || _accreditedConsumerProtectionLawyerToken.code.length == 0) + revert TokenNotSupported(_accreditedConsumerProtectionLawyerToken); + accreditedLawyerToken = _accreditedLawyerToken; + accreditedConsumerProtectionLawyerToken = _accreditedConsumerProtectionLawyerToken; }

73-83: Harden governance setters to prevent bricking via zero/EOA addresses.

Add the same validation as init.

 function changeAccreditedLawyerToken(address _accreditedLawyerToken) external onlyByOwner { - accreditedLawyerToken = _accreditedLawyerToken; + if (_accreditedLawyerToken == address(0) || _accreditedLawyerToken.code.length == 0) + revert TokenNotSupported(_accreditedLawyerToken); + accreditedLawyerToken = _accreditedLawyerToken; } @@ function changeAccreditedConsumerProtectionLawyerToken( address _accreditedConsumerProtectionLawyerToken ) external onlyByOwner { - accreditedConsumerProtectionLawyerToken = _accreditedConsumerProtectionLawyerToken; + if (_accreditedConsumerProtectionLawyerToken == address(0) || _accreditedConsumerProtectionLawyerToken.code.length == 0) + revert TokenNotSupported(_accreditedConsumerProtectionLawyerToken); + accreditedConsumerProtectionLawyerToken = _accreditedConsumerProtectionLawyerToken; }

112-138: Non‑terminating draw when no CP lawyers exist + unsafe token calls.

  • If no CP lawyers in the pool, the “last draw must be CP” rule causes perpetual redraws. Add a bounded retry fallback.
  • Also guard balanceOf on EOAs/zero and short‑circuit super._postDrawCheck first.
- ) internal view override returns (bool) { - if (IBalanceHolder(accreditedConsumerProtectionLawyerToken).balanceOf(_juror) == 0) { + ) internal view override returns (bool) { + // Short-circuit base checks first (e.g., singleDrawPerJuror) + if (!super._postDrawCheck(_round, _coreDisputeID, _juror, _roundNbVotes)) return false; + + bool isCPLawyer = ( + accreditedConsumerProtectionLawyerToken.code.length > 0 && + IBalanceHolder(accreditedConsumerProtectionLawyerToken).balanceOf(_juror) > 0 + ); + if (!isCPLawyer) { // The juror is not a consumer protection lawyer. uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID]; Dispute storage dispute = disputes[localDisputeID]; uint256 localRoundID = dispute.rounds.length - 1; if ( - dispute.rounds[localRoundID].votes.length == _roundNbVotes - 1 && - !drawnConsumerProtectionLawyer[localDisputeID][localRoundID] + dispute.rounds[localRoundID].votes.length == _roundNbVotes - 1 && + !drawnConsumerProtectionLawyer[localDisputeID][localRoundID] ) { - // This is the last draw iteration and we still have not drawn a consumer protection lawyer. - // Reject this draw so that another iteration can try again later. - return false; + // Last draw attempt; if we still have none, allow bounded extra attempts before accepting. + uint256 retries = extraDrawRetries[localDisputeID][localRoundID]; + if (retries < MAX_EXTRA_DRAW_RETRIES) { + unchecked { extraDrawRetries[localDisputeID][localRoundID] = retries + 1; } + return false; + } } - if (IBalanceHolder(accreditedLawyerToken).balanceOf(_juror) == 0) { + // Must at least hold the broader accredited lawyer token. + if ( + !(accreditedLawyerToken.code.length > 0 && + IBalanceHolder(accreditedLawyerToken).balanceOf(_juror) > 0) + ) { // The juror does not hold either of the tokens. return false; } } - return super._postDrawCheck(_round, _coreDisputeID, _juror, _roundNbVotes); + return true; }

Add storage for retries and a sane cap:

 contract DisputeKitGatedArgentinaConsumerProtection is DisputeKitClassicBase { @@ - mapping(uint256 localDisputeID => mapping(uint256 localRoundID => bool)) public drawnConsumerProtectionLawyer; // Maps the local dispute and round ID to the boolean indicating if the consumer protection lawyer was drawn. + mapping(uint256 localDisputeID => mapping(uint256 localRoundID => bool)) public drawnConsumerProtectionLawyer; // Maps the local dispute and round ID to the boolean indicating if the consumer protection lawyer was drawn. + mapping(uint256 localDisputeID => mapping(uint256 localRoundID => uint256)) private extraDrawRetries; + uint256 public constant MAX_EXTRA_DRAW_RETRIES = 64;
🧹 Nitpick comments (2)
contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol (1)

45-53: Validate POH address in initialize().

Guard against zero/EOA to avoid decode issues later.

 function initialize( @@ - ) external initializer { + ) external initializer { __DisputeKitClassicBase_initialize(_owner, _core, _wNative); - poh = _poh; + require(address(_poh) != address(0) && address(_poh).code.length > 0, "Invalid PoH"); + poh = _poh; singleDrawPerJuror = true; }
contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (1)

132-151: Guard balanceOf against EOAs/zero addresses.

A supported token can still be misconfigured; calling an interface function on an EOA/zero reverts on ABI decode. Short-circuit when tokenGate.code.length == 0.

- // Check juror's token balance - if (isERC1155) { + // Check juror's token balance + if (tokenGate.code.length == 0) return false; + if (isERC1155) { return IBalanceHolderERC1155(tokenGate).balanceOf(_juror, tokenId) > 0; } else { return IBalanceHolder(tokenGate).balanceOf(_juror) > 0; }

Optionally also validate in governance:

 function changeSupportedTokens(address[] memory _tokens, bool _supported) external onlyByOwner { for (uint256 i = 0; i < _tokens.length; i++) { - supportedTokens[_tokens[i]] = _supported; + if (_supported && _tokens[i] != NO_TOKEN_GATE) { + require(_tokens[i].code.length > 0, "Token must be a contract"); + } + supportedTokens[_tokens[i]] = _supported; } }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5f3079 and 7f64aba.

📒 Files selected for processing (5)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (3 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedArgentinaConsumerProtection.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.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). (14)
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header 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: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: hardhat-tests
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1)

256-278: LGTM! Signature update correctly implemented.

The _postDrawCheck function signature has been properly updated to accept the new _roundNbVotes parameter and forwards it to the superclass implementation. The existing token-gating validation logic remains intact and continues to function as expected.

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

69-77: Param plumbed correctly.

Forwarding _roundNbVotes to super._postDrawCheck and AND-ing with poh.isRegistered(_juror) looks good.

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

645-680: Court jump now keyed off _currentRoundNbVotes. Verify intended behavior.

Using the round’s nbVotes to decide court jump is a policy change. Ensure tests cover boundary: exactly equal to jurorsForJump and appeal sequences.


252-284: Draw plumbing verified: all dispute kits align on _roundNbVotes parameter.

All _postDrawCheck overrides include the _roundNbVotes parameter (DisputeKitGated, DisputeKitGatedArgentinaConsumerProtection, DisputeKitGatedShutter, DisputeKitSybilResistant). DisputeKitClassic and DisputeKitShutter inherit from DisputeKitClassicBase without override, inheriting the base implementation. DisputeKitClassicBase.draw() correctly passes _roundNbVotes to _postDrawCheck, and DisputeKitGatedArgentinaConsumerProtection.draw() correctly forwards it in the super call. Signatures and function plumbing are consistent across all implementations.

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 27, 2025
@jaybuidl jaybuidl merged commit 32fe70a into dev Oct 27, 2025
8 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2 participants