Skip to content

Release #2012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 157 commits into
base: master
Choose a base branch
from
Draft

Release #2012

wants to merge 157 commits into from

Conversation

jaybuidl
Copy link
Member

@jaybuidl jaybuidl commented May 28, 2025

Contract changes


PR-Codex overview

This PR focuses on enhancing the dispute resolution system by introducing new components and updating existing ones, particularly around the Shutter dispute kit, along with various improvements in the codebase for better functionality and maintainability.

Detailed summary

  • Deleted AllCasesButton component.
  • Introduced SeeAllCasesButton and SeeAllJurorsButton components.
  • Updated JustificationArea import paths.
  • Enhanced dispute-related components with new props and functionality.
  • Added disputeKit to the StakingResult enum.
  • Updated environment variables to include REACT_APP_SHUTTER_API.
  • Improved error handling in hooks and queries.
  • Adjusted various components to use the new disputeKit structure.
  • Updated package versions in package.json files.
  • Refactored function signatures to include new parameters for dispute handling.
  • Enhanced UI components for better responsiveness and user experience.
  • Added new contracts for DisputeKitGatedShutterProxy and DisputeKitShutterProxy.
  • Cleaned up unused code and comments across multiple files.

The following files were skipped due to too many changes: web/src/pages/Profile/index.tsx, subgraph/core/abi-migrations/KlerosCore.json, web/src/assets/svgs/icons/gavel-executed.svg, contracts/test/arbitration/draw.ts, web/src/pages/Cases/CaseDetails/Voting/index.tsx, subgraph/core/subgraph.yaml, web/src/pages/Cases/CaseDetails/Voting/Shutter/Reveal.tsx, subgraph/scripts/update.sh, web/src/components/DisputePreview/DisputeContext.tsx, web/src/components/EvidenceCard.tsx, subgraph/core/tests/sortition-module-utils.ts, web/src/components/Verdict/FinalDecision.tsx, contracts/test/arbitration/index.ts, subgraph/core-neo/abi-migrations/SortitionModuleNeo.json, contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol, web/src/pages/Cases/CaseDetails/Voting/Shutter/Commit.tsx, contracts/src/arbitration/dispute-kits/DisputeKitGated.sol, web/src/pages/Cases/CaseDetails/Appeal/Shutter/Fund.tsx, subgraph/core/abi-migrations/SortitionModule.json, subgraph/core-university/subgraph.template.yaml, web/src/utils/shutter.ts, subgraph/core/src/DisputeKitClassic.ts, yarn.lock, subgraph/core-neo/subgraph.template.yaml, web/src/components/Verdict/DisputeTimeline.tsx, subgraph/core/subgraph.template.yaml, contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol, contracts/src/arbitration/KlerosCoreBase.sol, contracts/scripts/shutter.ts, contracts/scripts/keeperBotShutter.ts, contracts/src/arbitration/university/KlerosCoreUniversity.sol, contracts/test/arbitration/dispute-kit-gated.ts, contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol, contracts/src/arbitration/university/SortitionModuleUniversity.sol, contracts/scripts/keeperBot.ts, contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter_Proxy.json, contracts/test/arbitration/staking.ts, contracts/test/arbitration/staking-neo.ts, contracts/src/arbitration/SortitionModuleBase.sol, contracts/test/foundry/KlerosCore.t.sol, contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter.json, contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter_Implementation.json

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

Summary by CodeRabbit

  • New Features

    • Added "See All" buttons for cases and jurors for easier navigation.
    • Introduced new contract functions exposing detailed dispute and court info.
    • Enabled jurors to withdraw leftover PNK tokens after fully unstaking.
    • Added Shutter dispute kit supporting encrypted vote commit and reveal.
    • Launched appeal crowdfunding UI and logic for Shutter dispute kit.
    • Added Shutter vote commit and reveal components with encryption integration.
    • Added new dispute kits with token gating and shielded voting capabilities.
    • Added ERC1155 test token contract and deployment support.
    • Added scripts for Shutter vote auto-reveal and encryption/decryption utilities.
    • Added new proxy contracts for DisputeKitGatedShutter and DisputeKitShutter.
  • Improvements

    • Enhanced layout and alignment in "Latest Cases" and "Top Jurors" sections.
    • Improved appeal countdown wording for clarity.
    • Added color styling for loading states in document viewer.
    • Added pre-check to avoid unnecessary juror draw attempts.
    • Context-sensitive navigation in attachment headers.
    • URLs for policy and evidence links now include dispute IDs.
    • Enhanced dispute context and labeling components.
    • Streamlined timeline and verdict components.
    • Added thousands separators in numeric displays.
    • Centralized user case statistics calculation.
    • Introduced filter sanitization utility for queries.
    • Improved accuracy in dispute event identification.
    • Separated stake validation and state updates in staking contracts.
    • Simplified delayed stake handling and unified related events.
    • Improved penalty accounting and juror inactivity handling.
    • Strengthened access control on stake-related functions.
    • Enhanced dispute lifecycle state management on appeal decisions.
    • Dynamic dispute kit ID handling in subgraph for multi-kit support.
    • Added support for multiple dispute kits in keeper bot and subgraph.
    • Improved shutdown handling and logging in keeper bot.
    • Integrated Shutter API for vote encryption and decryption.
    • Added Vite plugin to copy Shutter SDK static files.
    • Added environment variables for Shutter API endpoint.
    • Improved popup components to support automatic vote reveal messaging.
    • Refined staking and delayed stake event handling in tests.
    • Updated contract initialization routines and versioning.
    • Simplified and unified event handlers in subgraph and test utilities.
    • Enhanced dispute kit event handling with dynamic dispute kit IDs.
    • Improved contract deployment scripts with new dispute kits.
    • Improved staking logic with explicit leftover PNK withdrawal functions.
  • Bug Fixes

    • Added active-state checks to prevent operations on inactive disputes.
    • Corrected court ID boundary checks and error handling in staking logic.
    • Fixed staking and delayed stake event emissions and token balance assertions in tests.
    • Fixed event signature and parameter mismatches in subgraph and contracts.
    • Corrected vote casting logic for multiple dispute kits.
  • Chores

    • Updated documentation and package versions.
    • Removed unused components and redundant code.
    • Added script to analyze initializer versions across networks.
    • Consolidated event handlers and test utilities for simpler maintenance.
    • Added deployment and upgrade scripts for new dispute kits.
    • Added new subgraph manifests for Core Neo and University versions.
    • Added support for DisputeKitShutter in contract utilities.
    • Added new environment variable declarations for Shutter API in multiple environments.
    • Upgraded Node.js and devDependencies versions in contracts package.
    • Updated Yarn version in package configuration.

jaybuidl and others added 30 commits April 24, 2025 18:06
…ata sources not deployed

e.g. DisputeKitShutter on testnet
…ple-dispute-kit-above-id-1

feat: subgraph support for shutter disputekit in devnet
Comment on lines +275 to +280
} catch (e) {
logger.error(
`CastVoteShutter: will fail for disputeID: ${coreDispute.id} and voteIDs [${voteIDs.join(", ")}], skipping`
);
continue;
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored

<!--SONAR_ISSUE_KEY:AZgfpbfIRukU-uno1dHP-->Handle this exception or don't catch it at all. <p>See more on <a href="https://sonarcloud.io/project/issues?id=kleros_kleros-v2&issues=AZgfpbfIRukU-uno1dHP&open=AZgfpbfIRukU-uno1dHP&pullRequest=2012">SonarQube Cloud</a></p>
Comment on lines +93 to +95
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored

<!--SONAR_ISSUE_KEY:AZgfpbhVRukU-uno1dHQ-->Handle this exception or don't catch it at all. <p>See more on <a href="https://sonarcloud.io/project/issues?id=kleros_kleros-v2&issues=AZgfpbhVRukU-uno1dHQ&open=AZgfpbhVRukU-uno1dHQ&pullRequest=2012">SonarQube Cloud</a></p>
Comment on lines +129 to +131
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored

<!--SONAR_ISSUE_KEY:AZgfpbhVRukU-uno1dHR-->Handle this exception or don't catch it at all. <p>See more on <a href="https://sonarcloud.io/project/issues?id=kleros_kleros-v2&issues=AZgfpbhVRukU-uno1dHR&open=AZgfpbhVRukU-uno1dHR&pullRequest=2012">SonarQube Cloud</a></p>
Comment on lines +59 to +61
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored

<!--SONAR_ISSUE_KEY:AZgfpbk_RukU-uno1dHU-->Handle this exception or don't catch it at all. <p>See more on <a href="https://sonarcloud.io/project/issues?id=kleros_kleros-v2&issues=AZgfpbk_RukU-uno1dHU&open=AZgfpbk_RukU-uno1dHU&pullRequest=2012">SonarQube Cloud</a></p>
Comment on lines +96 to +98
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored

<!--SONAR_ISSUE_KEY:AZgfpbk_RukU-uno1dHV-->Handle this exception or don't catch it at all. <p>See more on <a href="https://sonarcloud.io/project/issues?id=kleros_kleros-v2&issues=AZgfpbk_RukU-uno1dHV&open=AZgfpbk_RukU-uno1dHV&pullRequest=2012">SonarQube Cloud</a></p>
fix(kleros-app): add-state-for-confirm-email
Comment on lines +275 to +280
} catch (e) {
logger.error(
`CastVoteShutter: will fail for disputeID: ${coreDispute.id} and voteIDs [${voteIDs.join(", ")}], skipping`
);
continue;
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored Low

Handle this exception or don't catch it at all. See more on SonarQube Cloud
Comment on lines +93 to +95
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored Low

Handle this exception or don't catch it at all. See more on SonarQube Cloud
Comment on lines +129 to +131
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored Low

Handle this exception or don't catch it at all. See more on SonarQube Cloud
Comment on lines +59 to +61
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored Low

Handle this exception or don't catch it at all. See more on SonarQube Cloud
Comment on lines +96 to +98
} catch (error) {
throw new Error(`Failed to parse API response as JSON: ${responseText}`);
}

Check notice

Code scanning / SonarCloud

Exceptions should not be ignored Low

Handle this exception or don't catch it at all. See more 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: 10

♻️ Duplicate comments (4)
contracts/scripts/shutter.ts (2)

93-95: Exception handling follows codebase patterns

The catch block that rethrows the error is intentional and follows the codebase error handling patterns.


129-131: Exception handling follows codebase patterns

The catch block that rethrows the error is intentional and follows the codebase error handling patterns.

contracts/test/foundry/KlerosCore.t.sol (1)

1359-1359: Fix misleading assertion message.

The assertion message "Wrong disputes length" doesn't match what's being tested. The test is checking coreDisputeIDToActive(0) which verifies whether the dispute is active, not the disputes length.

-        assertEq(disputeKit.coreDisputeIDToActive(0), true, "Wrong disputes length");
+        assertEq(disputeKit.coreDisputeIDToActive(0), true, "Dispute should be active");
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

67-67: Partial implementation of deactivation mechanism.

While the coreDisputeIDToActive mapping correctly addresses the need to track active dispute kits, the complete solution from the previous review is still missing. The past review specifically requested:

  1. ✅ Active dispute tracking (implemented)
  2. ❌ Explicit deactivateDispute function with onlyByCore modifier (missing)
  3. ❌ Integration with KlerosCore's dispute-kit switching logic (missing)

The existing test assertions mentioned in the past review likely still expect the deactivation API. Consider implementing the suggested deactivateDispute function:

function deactivateDispute(uint256 _coreDisputeID) external onlyByCore {
    delete coreDisputeIDToActive[_coreDisputeID];
    emit DisputeDeactivation(_coreDisputeID);
}
🧹 Nitpick comments (17)
web/.env.local.public (1)

9-9: Remove unnecessary quotes around the environment variable value.

The quotes around the URL are unnecessary and trigger a static analysis warning. Environment variable values don't require quotes unless they contain special characters.

-export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
+export REACT_APP_SHUTTER_API=https://shutter-api.chiado.staging.shutter.network/api
web/.env.devnet-neo.public (1)

12-12: Remove unnecessary quotes around the environment variable value.

Same issue as in other environment files - the quotes are unnecessary and trigger static analysis warnings.

-export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
+export REACT_APP_SHUTTER_API=https://shutter-api.chiado.staging.shutter.network/api
web/.env.devnet.public (1)

10-10: Remove unnecessary quotes and ensure consistency across all environment files.

Same formatting issue as other environment files. For consistency, remove quotes from the REACT_APP_SHUTTER_API value across all environment files.

-export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
+export REACT_APP_SHUTTER_API=https://shutter-api.chiado.staging.shutter.network/api

The consistent addition of this environment variable across all deployment environments is well done.

web/.env.testnet.public (1)

11-11: Consider reordering environment variables for consistency.

The addition of REACT_APP_SHUTTER_API is functionally correct and properly points to the staging Shutter API endpoint. However, consider moving this variable before REACT_APP_STATUS_URL to maintain alphabetical ordering consistency with other environment files.

 export REACT_APP_ATLAS_URI=http://localhost:3000
 export REACT_APP_DEVTOOLS_URL=https://devtools.v2-testnet.kleros.builders
+export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
+export REACT_APP_STATUS_URL=https://kleros-v2.betteruptime.com/badge
 export WALLETCONNECT_PROJECT_ID=
 export ALCHEMY_API_KEY=
 export NODE_OPTIONS='--max-old-space-size=7680'
-export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
web/.env.mainnet-neo.public (1)

11-12: Address formatting issues and verify API endpoint for mainnet.

Several formatting improvements needed:

  1. Missing blank line at end of file
  2. Consider reordering variables alphabetically for consistency

More importantly, verify if using the staging Shutter API endpoint (chiado.staging) is appropriate for the mainnet-neo environment, or if a production endpoint should be used instead.

 export REACT_APP_ARBITRATOR_TYPE=neo
 export REACT_APP_ATLAS_URI=http://localhost:3000
-export WALLETCONNECT_PROJECT_ID=
-export ALCHEMY_API_KEY=
 export NODE_OPTIONS='--max-old-space-size=7680'
 export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
+export WALLETCONNECT_PROJECT_ID=
+export ALCHEMY_API_KEY=
+

Please verify if a production Shutter API endpoint should be used for mainnet-neo instead of the staging endpoint.

web/.env.devnet-university.public (1)

11-11: Reorder environment variable for consistency.

The addition of REACT_APP_SHUTTER_API is appropriate for the devnet environment. Consider moving this variable before REACT_APP_STATUS_URL to maintain alphabetical ordering consistency across environment files.

 export REACT_APP_ARBITRATOR_TYPE=university
 export REACT_APP_ATLAS_URI=http://localhost:3000
+export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
+export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge
 export WALLETCONNECT_PROJECT_ID=
 export ALCHEMY_API_KEY=
 export NODE_OPTIONS='--max-old-space-size=7680'
-export REACT_APP_SHUTTER_API="https://shutter-api.chiado.staging.shutter.network/api"
subgraph/core/src/entities/ClassicDispute.ts (1)

1-1: Consider the BigInt import naming.

While functionally correct, the static analysis tool flags that importing BigInt from @graphprotocol/graph-ts shadows the global BigInt property. This is a common pattern in Graph Protocol subgraphs and generally acceptable, but be aware of the potential for confusion.

subgraph/core/src/entities/ClassicContribution.ts (1)

13-19: Minor naming inconsistency between roundId and roundID.

Consider using consistent casing for variable names - currently using both roundId (line 13) and roundID (line 19).

-  const roundId = `${coreDisputeID}-${coreRoundIndex}`;
-  const coreRound = Round.load(roundId);
+  const roundID = `${coreDisputeID}-${coreRoundIndex}`;
+  const coreRound = Round.load(roundID);
web/src/pages/Cases/CaseDetails/Voting/index.tsx (1)

73-76: Consider using more robust dispute kit type detection.

The current string-based matching using includes("classic") and includes("shutter") works but could be more robust. Consider using exact string matches or enum values for better type safety.

-  const isClassicDisputeKit = disputeKitName?.toLowerCase().includes("classic") ?? false;
-  const isShutterDisputeKit = disputeKitName?.toLowerCase().includes("shutter") ?? false;
+  const isClassicDisputeKit = disputeKitName?.toLowerCase() === "classic dispute kit";
+  const isShutterDisputeKit = disputeKitName?.toLowerCase() === "shutter dispute kit";
web/src/pages/Cases/CaseDetails/Appeal/Shutter/index.tsx (1)

44-44: Consider improving type safety for amount prop.

The type assertion amount as \${number}`` could be unsafe if amount contains non-numeric characters. Consider validating the amount before passing it.

-      <Fund amount={amount as `${number}`} setAmount={setAmount} setIsOpen={setIsPopupOpen} />
+      <Fund amount={amount} setAmount={setAmount} setIsOpen={setIsPopupOpen} />

Let the Fund component handle the type validation internally, or validate the amount before passing it.

web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx (1)

26-31: Consider improving readability of the conditional rendering logic.

While the logic is correct, the nested ternary operators make it harder to understand the different rendering states.

Consider refactoring for better readability:

-  return id && isCommitPeriod && !commited ? (
-    <ShutterCommit {...{ arbitrable, setIsOpen, voteIDs, refetch, dispute, currentPeriodIndex }} />
-  ) : id && isVotingPeriod ? (
-    <Reveal {...{ setIsOpen, voteIDs }} />
-  ) : null;
+  if (!id) return null;
+  
+  if (isCommitPeriod && !commited) {
+    return <ShutterCommit {...{ arbitrable, setIsOpen, voteIDs, refetch, dispute, currentPeriodIndex }} />;
+  }
+  
+  if (isVotingPeriod) {
+    return <Reveal {...{ setIsOpen, voteIDs }} />;
+  }
+  
+  return null;
contracts/scripts/keeperBotShutter.ts (1)

302-305: Remove unnecessary continue statement.

The continue statement at the end of the loop iteration is redundant.

       } catch (e) {
         logger.error(e, "Failure");
-        continue;
       }
subgraph/core-neo/subgraph.template.yaml (1)

141-143: Address the temporary ABI override.

There's a FIX comment indicating a temporary ABI file is being used. This should be resolved before the final release.

Would you like me to help identify what event additions are needed in the main ABI file or create an issue to track this technical debt?

web/src/pages/Cases/CaseDetails/Appeal/Shutter/Fund.tsx (1)

117-119: Consider adding input validation for amount field

The number input accepts any value without validation. Consider adding min/max constraints and step precision.

       <StyledField
         type="number"
         value={amount}
         onChange={(e) => setAmount(e.target.value)}
         placeholder="Amount to fund"
+        min="0"
+        step="0.01"
       />
contracts/scripts/shutter.ts (1)

172-177: Consider Node.js compatibility for random byte generation

The code uses crypto.getRandomValues which is a Web Crypto API. For better Node.js compatibility, consider using crypto.randomBytes.

 function generateRandomBytes32(): `0x${string}` {
-  return ("0x" +
-    crypto
-      .getRandomValues(new Uint8Array(32))
-      .reduce((acc, byte) => acc + byte.toString(16).padStart(2, "0"), "")) as Hex;
+  const bytes = crypto.randomBytes(32);
+  return ("0x" + bytes.toString("hex")) as Hex;
 }
web/src/pages/Cases/CaseDetails/Voting/Shutter/Commit.tsx (1)

66-66: Unused localStorage value

The first element from useLocalStorage is destructured as _ but never used. Consider if you need to read existing values or remove the unused variable.

-  const [_, setSalt] = useLocalStorage(saltKey);
+  const [, setSalt] = useLocalStorage(saltKey);
contracts/scripts/keeperBot.ts (1)

524-527: Consider explicit log flushing instead of delay.

While the delay works, a more robust approach would be to explicitly flush the logger if the logging library supports it.

Check if the logger supports explicit flushing:

const shutdown = async () => {
  logger.info("Shutting down");
  // If logger supports flushing
  if (typeof logger.flush === 'function') {
    await logger.flush();
  } else {
    await delay(2000); // Fallback to delay
  }
};

Comment on lines +60 to 68
<>
{isClassicDisputeKit && (
<Classic isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} />
)}
{isShutterDisputeKit && (
<Shutter isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} />
)}
</>
) : (
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider fallback rendering for unknown dispute kit types.

If neither isClassicDisputeKit nor isShutterDisputeKit evaluates to true (e.g., for unknown dispute kit types or loading states), no appeal component will render. Consider adding a fallback or loading state.

        <>
          {isClassicDisputeKit && (
            <Classic isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} />
          )}
          {isShutterDisputeKit && (
            <Shutter isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} />
          )}
+         {!isClassicDisputeKit && !isShutterDisputeKit && disputeKitName && (
+           <div>Unsupported dispute kit: {disputeKitName}</div>
+         )}
        </>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<>
{isClassicDisputeKit && (
<Classic isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} />
)}
{isShutterDisputeKit && (
<Shutter isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} />
)}
</>
) : (
<>
{isClassicDisputeKit && (
<Classic
isAppealMiniGuideOpen={isAppealMiniGuideOpen}
toggleAppealMiniGuide={toggleAppealMiniGuide}
/>
)}
{isShutterDisputeKit && (
<Shutter
isAppealMiniGuideOpen={isAppealMiniGuideOpen}
toggleAppealMiniGuide={toggleAppealMiniGuide}
/>
)}
{!isClassicDisputeKit && !isShutterDisputeKit && disputeKitName && (
<div>Unsupported dispute kit: {disputeKitName}</div>
)}
</>
) : (
🤖 Prompt for AI Agents
In web/src/pages/Cases/CaseDetails/Appeal/index.tsx around lines 60 to 68, the
current code only renders appeal components for known dispute kit types (Classic
and Shutter) and does not handle cases where neither condition is true. Add a
fallback UI element or loading state to render when both isClassicDisputeKit and
isShutterDisputeKit are false, ensuring the UI handles unknown dispute kit types
or loading scenarios gracefully.

const { address } = useAccount();
const { data: drawData, refetch } = useDrawQuery(address?.toLowerCase(), id, dispute?.currentRound.id);
const { isCommitPeriod, isVotingPeriod, commited } = useVotingContext();
const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) as string[], [drawData]);
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

Fix unsafe type assertion that could cause runtime errors.

The type assertion as string[] is unsafe because when drawData?.draws is undefined, the expression evaluates to undefined, not string[]. This could cause runtime errors in child components.

Apply this fix to handle undefined cases properly:

-  const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) as string[], [drawData]);
+  const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) ?? [], [drawData]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) as string[], [drawData]);
const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) ?? [], [drawData]);
🤖 Prompt for AI Agents
In web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx at line 24, the
useMemo hook uses an unsafe type assertion 'as string[]' which can cause runtime
errors if drawData?.draws is undefined. To fix this, modify the expression to
safely handle undefined by returning an empty array or a default value when
drawData?.draws is undefined, ensuring the result is always a string array and
preventing runtime errors in child components.

async function main() {
logger.debug("Starting...");
const { disputeKitShutter } = await getContracts();
await shutterAutoReveal(disputeKitShutter, ["44", "45", "51", "54"]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Make the disputes skip list configurable.

The hardcoded dispute IDs should be moved to an environment variable or configuration file for better maintainability.

-  await shutterAutoReveal(disputeKitShutter, ["44", "45", "51", "54"]);
+  const disputesToSkip = env.optional("DISPUTES_TO_SKIP", "").split(",").filter(Boolean);
+  await shutterAutoReveal(disputeKitShutter, disputesToSkip);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await shutterAutoReveal(disputeKitShutter, ["44", "45", "51", "54"]);
const disputesToSkip = env.optional("DISPUTES_TO_SKIP", "").split(",").filter(Boolean);
await shutterAutoReveal(disputeKitShutter, disputesToSkip);
🤖 Prompt for AI Agents
In contracts/scripts/keeperBotShutter.ts at line 313, the dispute IDs passed to
shutterAutoReveal are hardcoded. To fix this, move the array ["44", "45", "51",
"54"] into an environment variable or a configuration file, then read and parse
that configuration at runtime and pass the resulting list to shutterAutoReveal
instead of the hardcoded array.

Comment on lines +65 to +67
BigInt(parsedStoredData?.choice ?? 0),
BigInt(parsedStoredData?.salt ?? 0),
parsedStoredData?.justification ?? "",
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for BigInt conversion

The code uses BigInt(parsedStoredData?.choice ?? 0) and BigInt(parsedStoredData?.salt ?? 0) without validating that the stored values are valid numeric strings. This could throw an error if the data is corrupted.

Consider adding validation:

+    const choiceValue = parsedStoredData?.choice;
+    const saltValue = parsedStoredData?.salt;
+    const isValidBigInt = (value: unknown): boolean => {
+      try {
+        return typeof value === 'string' && !isNaN(Number(value));
+      } catch {
+        return false;
+      }
+    };
+
     args: [
       parsedDisputeID,
       parsedVoteIDs,
-      BigInt(parsedStoredData?.choice ?? 0),
-      BigInt(parsedStoredData?.salt ?? 0),
+      isValidBigInt(choiceValue) ? BigInt(choiceValue) : BigInt(0),
+      isValidBigInt(saltValue) ? BigInt(saltValue) : BigInt(0),
       parsedStoredData?.justification ?? "",
     ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
BigInt(parsedStoredData?.choice ?? 0),
BigInt(parsedStoredData?.salt ?? 0),
parsedStoredData?.justification ?? "",
const choiceValue = parsedStoredData?.choice;
const saltValue = parsedStoredData?.salt;
const isValidBigInt = (value: unknown): boolean => {
try {
return typeof value === 'string' && !isNaN(Number(value));
} catch {
return false;
}
};
args: [
parsedDisputeID,
parsedVoteIDs,
isValidBigInt(choiceValue) ? BigInt(choiceValue) : BigInt(0),
isValidBigInt(saltValue) ? BigInt(saltValue) : BigInt(0),
parsedStoredData?.justification ?? "",
],
🤖 Prompt for AI Agents
In web/src/pages/Cases/CaseDetails/Voting/Shutter/Reveal.tsx around lines 65 to
67, the code converts parsedStoredData.choice and parsedStoredData.salt to
BigInt without validating if they are valid numeric strings, which can cause
runtime errors if the data is corrupted. Add validation to check if these values
are valid numeric strings before converting to BigInt, and handle invalid cases
gracefully, such as by defaulting to 0 or showing an error message.

Comment on lines +157 to +162
eventHandlers:
- event: StakeLocked(indexed address,uint256,bool)
handler: handleStakeLocked
- event: StakeSet(indexed address,uint256,uint256,uint256)
handler: handleStakeSet
file: ./src/SortitionModule.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify SortitionModule event handlers

The SortitionModule only handles StakeLocked and StakeSet events. Based on the PR summary mentioning consolidation of stake delay events into StakeDelayed, verify if this event should be included.


🏁 Script executed:

#!/bin/bash
# Check for StakeDelayed event in SortitionModule contracts
echo "=== Searching for StakeDelayed event definition ==="
rg "event StakeDelayed" --type sol

echo -e "\n=== Check other subgraph manifests for StakeDelayed handlers ==="
fd -e yaml -e yml | xargs rg "StakeDelayed" -A 2 -B 2

Length of output: 3649


This will confirm whether the StakeDelayed event is defined in the SortitionModule contract before deciding if it should be added to the university subgraph manifest.


🏁 Script executed:

#!/bin/bash
echo "=== Locating SortitionModule.sol ==="
fd -e sol SortitionModule.sol

echo -e "\n=== Searching for StakeDelayed occurrences in all .sol files ==="
rg -n "StakeDelayed" --glob "*.sol"

Length of output: 1267


🏁 Script executed:

#!/bin/bash
echo "=== Searching for handleStakeDelayed in TypeScript mappings ==="
rg -n "handleStakeDelayed" --glob "*.ts"

Length of output: 280


Add missing StakeDelayed handler to SortitionModule data source

The StakeDelayed event is defined in SortitionModuleBase.sol and emitted by the module, and you already have a corresponding handleStakeDelayed mapping in your TypeScript. Other subgraphs include this event before StakeLocked. To ensure the university subgraph indexes the consolidated “stake delay” event, add its handler:

• Confirmed event StakeDelayed(address indexed _address, uint96 indexed _courtID, uint256 _amount) in contracts/src/arbitration/SortitionModuleBase.sol
• Found export function handleStakeDelayed(event: StakeDelayed): void { … } in subgraph/core/src/SortitionModule.ts
• Core and core-neo manifests include:

  • event: StakeDelayed(indexed address,indexed uint96,uint256)
    handler: handleStakeDelayed

Update subgraph/core-university/subgraph.template.yaml accordingly:

@@ -157,7 +157,10 @@ dataSources:
       eventHandlers:
-        - event: StakeLocked(indexed address,uint256,bool)
+        - event: StakeDelayed(indexed address,indexed uint96,uint256)
+          handler: handleStakeDelayed
+        - event: StakeLocked(indexed address,uint256,bool)
         - event: StakeSet(indexed address,uint256,uint256,uint256)
           handler: handleStakeSet
       file: ./src/SortitionModule.ts
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
eventHandlers:
- event: StakeLocked(indexed address,uint256,bool)
handler: handleStakeLocked
- event: StakeSet(indexed address,uint256,uint256,uint256)
handler: handleStakeSet
file: ./src/SortitionModule.ts
eventHandlers:
- event: StakeDelayed(indexed address,indexed uint96,uint256)
handler: handleStakeDelayed
- event: StakeLocked(indexed address,uint256,bool)
handler: handleStakeLocked
- event: StakeSet(indexed address,uint256,uint256,uint256)
handler: handleStakeSet
file: ./src/SortitionModule.ts
🤖 Prompt for AI Agents
In subgraph/core-university/subgraph.template.yaml around lines 157 to 162, the
event handler for the StakeDelayed event is missing from the SortitionModule
data source. Add a new event handler entry for StakeDelayed with the signature
"StakeDelayed(indexed address,indexed uint96,uint256)" and set its handler to
"handleStakeDelayed" before the existing StakeLocked event handler to ensure the
subgraph indexes this event correctly.

Comment on lines +68 to +72
# initialize from template
template="${subgraphConfig%.yaml}.template.yaml"
echo '# THIS FILE IS AUTO-GENERATED BY update.sh FROM subgraph.template.yaml, ANY CHANGES WILL BE LOST.' > "$subgraphConfig"
cat "$template" >>"$subgraphConfig"

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add template file existence check before initialization.

The script should verify that the template file exists before attempting to use it.

Add this check before line 70:

if [ ! -f "$template" ]; then
    echo -e "\e[1;31mError: Template file $template not found\e[0m"
    exit 1
fi
🤖 Prompt for AI Agents
In subgraph/scripts/update.sh around lines 68 to 72, add a check to verify that
the template file exists before using it. Insert an if statement before line 70
that tests if the template file does not exist, and if so, print an error
message and exit the script with status 1. This prevents the script from
proceeding with a missing template file.

local dataSourceName="$5"

# Get the deployment artifact
local contractName=$(basename $(yq '.dataSources['$dataSourceIndex'].mapping.abis[] | select(.name == "'$dataSourceName'") | .file' "$subgraphConfig") .json)
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

Fix shellcheck warnings for safer command substitution.

The current implementation has potential issues with word splitting and masked return values.

-    local contractName=$(basename $(yq '.dataSources['$dataSourceIndex'].mapping.abis[] | select(.name == "'$dataSourceName'") | .file' "$subgraphConfig") .json)
+    local abiFile
+    abiFile=$(yq '.dataSources['$dataSourceIndex'].mapping.abis[] | select(.name == "'$dataSourceName'") | .file' "$subgraphConfig")
+    local contractName
+    contractName=$(basename "$abiFile" .json)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
local contractName=$(basename $(yq '.dataSources['$dataSourceIndex'].mapping.abis[] | select(.name == "'$dataSourceName'") | .file' "$subgraphConfig") .json)
local abiFile
abiFile=$(yq '.dataSources['$dataSourceIndex'].mapping.abis[] | select(.name == "'$dataSourceName'") | .file' "$subgraphConfig")
local contractName
contractName=$(basename "$abiFile" .json)
🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 13-13: Declare and assign separately to avoid masking return values.

(SC2155)


[warning] 13-13: Quote this to prevent word splitting.

(SC2046)

🤖 Prompt for AI Agents
In subgraph/scripts/update.sh at line 13, the command substitution uses unquoted
variables and nested substitutions that can cause word splitting and mask
errors. To fix this, use double quotes around variable expansions and command
substitutions, and consider using arrays or safer parsing methods to prevent
word splitting. This will make the script more robust and avoid shellcheck
warnings.

Comment on lines +85 to +88
for i in "${notDeployedSourceIndices[@]}"; do
echo -e "\e[1;31mDeleting data source $i\e[0m"
yq -i 'del(.dataSources['$i'])' "$subgraphConfig"
done
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

Fix array index shifting issue when deleting multiple data sources.

Deleting array elements by index causes remaining indices to shift, leading to incorrect deletions when multiple contracts are undeployed.

-# delete the data sources for the contracts that are not deployed
-for i in "${notDeployedSourceIndices[@]}"; do
-    echo -e "\e[1;31mDeleting data source $i\e[0m"
-    yq -i 'del(.dataSources['$i'])' "$subgraphConfig"
-done
+# delete the data sources for the contracts that are not deployed (in reverse order to avoid index shifting)
+for (( idx=${#notDeployedSourceIndices[@]}-1 ; idx>=0 ; idx-- )) ; do
+    i="${notDeployedSourceIndices[idx]}"
+    echo -e "\e[1;31mDeleting data source $i\e[0m"
+    yq -i 'del(.dataSources['$i'])' "$subgraphConfig"
+done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for i in "${notDeployedSourceIndices[@]}"; do
echo -e "\e[1;31mDeleting data source $i\e[0m"
yq -i 'del(.dataSources['$i'])' "$subgraphConfig"
done
# delete the data sources for the contracts that are not deployed (in reverse order to avoid index shifting)
for (( idx=${#notDeployedSourceIndices[@]}-1; idx>=0; idx-- )); do
i="${notDeployedSourceIndices[idx]}"
echo -e "\e[1;31mDeleting data source $i\e[0m"
yq -i 'del(.dataSources['$i'])' "$subgraphConfig"
done
🤖 Prompt for AI Agents
In subgraph/scripts/update.sh around lines 85 to 88, deleting data sources by
iterating over indices in ascending order causes index shifting and incorrect
deletions. To fix this, reverse the order of indices in notDeployedSourceIndices
before the loop so that deletions start from the highest index, preventing
shifts from affecting subsequent deletions.

Comment on lines +89 to +101
function castVoteShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
uint256 _choice,
uint256 _salt,
string memory _justification
) external {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
address juror = dispute.rounds[dispute.rounds.length - 1].votes[_voteIDs[0]].account;

// _castVote() ensures that all the _voteIDs do belong to `juror`
_castVote(_coreDisputeID, _voteIDs, _choice, _salt, _justification, juror);
}
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

Add array bounds check to prevent potential revert.

The function accesses _voteIDs[0] without verifying the array is non-empty.

 function castVoteShutter(
     uint256 _coreDisputeID,
     uint256[] calldata _voteIDs,
     uint256 _choice,
     uint256 _salt,
     string memory _justification
 ) external {
+    require(_voteIDs.length > 0, "No vote IDs provided");
     Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
     address juror = dispute.rounds[dispute.rounds.length - 1].votes[_voteIDs[0]].account;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function castVoteShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
uint256 _choice,
uint256 _salt,
string memory _justification
) external {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
address juror = dispute.rounds[dispute.rounds.length - 1].votes[_voteIDs[0]].account;
// _castVote() ensures that all the _voteIDs do belong to `juror`
_castVote(_coreDisputeID, _voteIDs, _choice, _salt, _justification, juror);
}
function castVoteShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
uint256 _choice,
uint256 _salt,
string memory _justification
) external {
require(_voteIDs.length > 0, "No vote IDs provided");
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
address juror = dispute
.rounds[dispute.rounds.length - 1]
.votes[_voteIDs[0]]
.account;
// _castVote() ensures that all the _voteIDs do belong to `juror`
_castVote(_coreDisputeID, _voteIDs, _choice, _salt, _justification, juror);
}
🤖 Prompt for AI Agents
In contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol around lines 89
to 101, the function castVoteShutter accesses _voteIDs[0] without checking if
the _voteIDs array is non-empty, which can cause a runtime error. Add a require
statement at the start of the function to ensure _voteIDs.length is greater than
zero before accessing _voteIDs[0]. This will prevent potential out-of-bounds
errors and reverts.

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 (2)
contracts/src/arbitration/university/SortitionModuleUniversity.sol (2)

55-58: Consider when to emit the LeftoverPNK event.

The LeftoverPNK event is declared but never emitted in the contract. Consider emitting this event when leftover PNK becomes available (e.g., when a juror fully unstakes or when locked tokens are unlocked and create a leftover situation).

    function unlockStake(address _account, uint256 _relativeAmount) external override onlyByCore {
        jurors[_account].lockedPnk -= _relativeAmount;
+       uint256 leftover = getJurorLeftoverPNK(_account);
+       if (leftover > 0) {
+           emit LeftoverPNK(_account, leftover);
+       }
        emit StakeLocked(_account, _relativeAmount, true);
    }

279-287: Well-implemented function for handling leftover PNK edge case.

The withdrawLeftoverPNK function properly addresses the scenario where jurors have remaining staked PNK after fully unstaking and having no locked tokens. The implementation is secure:

  • Proper eligibility check via getJurorLeftoverPNK
  • Correct state updates (resetting stakedPnk to 0)
  • Appropriate use of core contract for token transfer
  • Proper event emission

Consider adding more detailed documentation about the specific scenarios when leftover PNK can occur to help users understand when this function is applicable.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2b11e6d and 2116239.

📒 Files selected for processing (1)
  • contracts/src/arbitration/university/SortitionModuleUniversity.sol (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
Learnt from: kemuru
PR: kleros/kleros-v2#1702
File: web/src/pages/Home/TopJurors/JurorCard/index.tsx:10-11
Timestamp: 2024-10-08T16:23:56.291Z
Learning: In the `kleros-v2` codebase, the property `totalResolvedDisputes` should remain and should not be renamed to `totalResolvedVotes`.
Learnt from: kemuru
PR: kleros/kleros-v2#1702
File: web/src/pages/Home/TopJurors/JurorCard/index.tsx:10-11
Timestamp: 2024-10-07T06:18:23.427Z
Learning: In the `kleros-v2` codebase, the property `totalResolvedDisputes` should remain and should not be renamed to `totalResolvedVotes`.
contracts/src/arbitration/university/SortitionModuleUniversity.sol (3)
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.
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`.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1744
File: web/src/hooks/useGenesisBlock.ts:9-31
Timestamp: 2024-11-19T05:31:48.701Z
Learning: In `useGenesisBlock.ts`, within the `useEffect` hook, the conditions (`isKlerosUniversity`, `isKlerosNeo`, `isTestnetDeployment`) are mutually exclusive, so multiple imports won't execute simultaneously, and race conditions are not a concern.
⏰ 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). (6)
  • GitHub Check: SonarCloud
  • GitHub Check: Analyze (javascript)
  • GitHub Check: contracts-testing
  • GitHub Check: SonarCloud
  • GitHub Check: contracts-testing
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
contracts/src/arbitration/university/SortitionModuleUniversity.sol (5)

139-173: Well-designed validation function with proper edge case handling.

The validateStake function effectively separates validation logic from state changes, which is a good architectural pattern. The validation checks are comprehensive:

  • Prevents staking beyond MAX_STAKE_PATHS
  • Forbids zero staking when no existing stake exists
  • Properly calculates withdrawal limits based on locked tokens

The withdrawal calculation correctly handles the edge case where lockedPnk might exceed stakedPnk.


186-228: Solid implementation of the state mutation logic.

The setStake function correctly applies the validated changes:

  • Properly manages the courtIDs array with efficient removal logic
  • Updates juror balances accurately
  • Maintains the court hierarchy staking mechanism
  • Emits appropriate events

The separation between validation (validateStake) and state mutation (setStake) follows good design principles.


240-257: Improved function interface with useful return values.

The updated penalizeStake function now returns both the juror's remaining PNK balance and the actual penalty applied. This is a significant improvement as it allows callers to:

  • Know exactly how much penalty was actually applied
  • Get the updated balance without additional calls
  • Handle cases where the requested penalty exceeds available tokens

The logic correctly caps penalties at the available staked PNK amount.


269-269: Function call updated to match new core contract signature.

The removal of the boolean parameter aligns with the interface changes mentioned in the AI summary. This maintains consistency with the updated setStakeBySortitionModule function signature in the core contracts.


340-346: Clear and correct logic for determining leftover PNK eligibility.

The getJurorLeftoverPNK function correctly identifies when a juror has leftover staked PNK that can be withdrawn. The conditions are appropriate:

  • No active court stakes (courtIDs.length == 0)
  • No locked tokens (lockedPnk == 0)
  • Has positive staked PNK balance

This handles the edge case where async operations (unstaking during disputes and later token unlocking) can leave jurors with withdrawable leftover tokens.

const arbitrationCost = await core["arbitrationCost(bytes)"](extraData);

// Warning: this dispute cannot be executed, in reality it should be created by an arbitrable contract, not an EOA.
const tx = await core["createDispute(uint256,bytes)"](2, extraData, { value: arbitrationCost }).then((tx) =>

Check notice

Code scanning / SonarCloud

Unused assignments should be removed

<!--SONAR_ISSUE_KEY:AZgkRfXWOA3YISovWvD2-->Remove this useless assignment to variable "tx". <p>See more on <a href="https://sonarcloud.io/project/issues?id=kleros_kleros-v2&issues=AZgkRfXWOA3YISovWvD2&open=AZgkRfXWOA3YISovWvD2&pullRequest=2012">SonarQube Cloud</a></p>
const arbitrationCost = await core["arbitrationCost(bytes)"](extraData);

// Warning: this dispute cannot be executed, in reality it should be created by an arbitrable contract, not an EOA.
const tx = await core["createDispute(uint256,bytes)"](2, extraData, { value: arbitrationCost }).then((tx) =>

Check notice

Code scanning / SonarCloud

Unused assignments should be removed Low test

Remove this useless assignment to variable "tx". See more 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: 6

🧹 Nitpick comments (6)
contracts/src/token/TestERC1155.sol (1)

27-30: Use custom errors instead of require strings for gas optimization.

Since Solidity 0.8.4, custom errors are more gas-efficient than require statements with strings.

+error NotOwner();

 modifier ownerOnly() {
-    require(msg.sender == owner, "Owner only");
+    if (msg.sender != owner) revert NotOwner();
     _;
 }
contracts/test/arbitration/dispute-kit-gated.ts (1)

133-135: Consider adding a test helper contract for proper dispute creation.

The comment indicates this test creates disputes incorrectly from an EOA. This could mask potential issues.

Consider deploying a minimal arbitrable contract for testing:

// Deploy a test arbitrable contract
await deployments.deploy("TestArbitrable", {
  from: deployer,
  args: [core.target],
  log: true,
});
const arbitrable = await ethers.getContract("TestArbitrable");

// Use the arbitrable to create disputes instead of EOA
const tx = await arbitrable.createDispute(2, extraData, { value: arbitrationCost });

Would you like me to generate a minimal TestArbitrable contract for proper dispute creation in tests?

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

62-87: Well-implemented token info extraction with minor comment clarification needed.

The function correctly extracts token gating parameters from extraData using efficient assembly operations. The bit packing/unpacking logic is sound.

Consider clarifying the comment on line 81 - the offset 160 (0xA0) is the standard position for the 5th parameter, not "moved up".

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

7-21: Consider extracting shared interfaces to reduce duplication.

The IBalanceHolder and IBalanceHolderERC1155 interfaces are duplicated from DisputeKitGated.sol. Consider extracting these to a shared interface file to follow DRY principles.


149-164: Consider extracting common token info extraction logic.

This function is identical to extraDataToTokenInfo in DisputeKitGated.sol except for visibility. Consider extracting this logic to a shared library to avoid code duplication.


167-188: Correct token gating implementation with code duplication.

The token gating logic is implemented correctly and consistently with DisputeKitGated. However, this entire function is duplicated from DisputeKitGated._postDrawCheck.

Consider creating a shared base contract (e.g., DisputeKitGatedBase) that both DisputeKitGated and DisputeKitGatedShutter can inherit from to avoid this duplication.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2116239 and 358a621.

📒 Files selected for processing (11)
  • contracts/deploy/00-home-chain-arbitration.ts (2 hunks)
  • contracts/deploy/utils/deployTokens.ts (1 hunks)
  • contracts/hardhat.config.ts (2 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (3 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol (1 hunks)
  • contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol (1 hunks)
  • contracts/src/proxy/KlerosProxies.sol (1 hunks)
  • contracts/src/token/TestERC1155.sol (1 hunks)
  • contracts/test/arbitration/dispute-kit-gated.ts (1 hunks)
  • contracts/test/arbitration/draw.ts (7 hunks)
  • contracts/test/arbitration/index.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • contracts/test/arbitration/draw.ts
  • contracts/src/proxy/KlerosProxies.sol
  • contracts/test/arbitration/index.ts
  • contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
Learnt from: kemuru
PR: kleros/kleros-v2#1702
File: web/src/pages/Home/TopJurors/JurorCard/index.tsx:10-11
Timestamp: 2024-10-08T16:23:56.291Z
Learning: In the `kleros-v2` codebase, the property `totalResolvedDisputes` should remain and should not be renamed to `totalResolvedVotes`.
Learnt from: kemuru
PR: kleros/kleros-v2#1702
File: web/src/pages/Home/TopJurors/JurorCard/index.tsx:10-11
Timestamp: 2024-10-07T06:18:23.427Z
Learning: In the `kleros-v2` codebase, the property `totalResolvedDisputes` should remain and should not be renamed to `totalResolvedVotes`.
contracts/hardhat.config.ts (1)
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1687
File: web/src/context/AtlasProvider.tsx:225-244
Timestamp: 2024-10-15T16:18:32.543Z
Learning: In `web/src/context/AtlasProvider.tsx`, the `atlasUri` variable comes from environment variables and does not change, so it does not need to be included in dependency arrays.
contracts/deploy/00-home-chain-arbitration.ts (8)
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: kleros-sdk/src/utils/getDispute.ts:38-40
Timestamp: 2024-10-21T10:32:16.970Z
Learning: The variables 'arbitrableChainID' and 'externalDisputeID' are required by the context to have uppercase 'ID', so they should remain unchanged even if the corresponding source properties use 'Id'.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: web/src/hooks/queries/usePopulatedDisputeData.ts:58-61
Timestamp: 2024-10-14T13:58:25.708Z
Learning: In `web/src/hooks/queries/usePopulatedDisputeData.ts`, the query and subsequent logic only execute when `disputeData.dispute?.arbitrableChainId` and `disputeData.dispute?.externalDisputeId` are defined, so `initialContext` properties based on these values are safe to use without additional null checks.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1744
File: web/src/hooks/useGenesisBlock.ts:9-31
Timestamp: 2024-11-19T05:31:48.701Z
Learning: In `useGenesisBlock.ts`, within the `useEffect` hook, the conditions (`isKlerosUniversity`, `isKlerosNeo`, `isTestnetDeployment`) are mutually exclusive, so multiple imports won't execute simultaneously, and race conditions are not a concern.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: kleros-sdk/src/sdk.ts:1-3
Timestamp: 2024-10-22T10:23:15.789Z
Learning: In `kleros-sdk/src/sdk.ts`, the `PublicClient` type is used and should not be flagged as unused.
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.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1846
File: prettier-config/index.js:26-26
Timestamp: 2025-01-23T08:14:47.397Z
Learning: The prettier-plugin-solidity plugin is installed in the kleros-v2 repository, even though it's not visible in the sandbox environment's node_modules (which is expected as node_modules is not committed to the repository).
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: kleros-sdk/src/requests/gqlClient.ts:18-18
Timestamp: 2024-10-24T08:16:02.749Z
Learning: In this TypeScript project, when a file (such as `kleros-sdk/src/requests/gqlClient.ts`) exports only a single entity, it's acceptable to use default exports instead of named exports.
contracts/src/arbitration/dispute-kits/DisputeKitGated.sol (3)
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: kleros-sdk/src/utils/getDispute.ts:38-40
Timestamp: 2024-10-21T10:32:16.970Z
Learning: The variables 'arbitrableChainID' and 'externalDisputeID' are required by the context to have uppercase 'ID', so they should remain unchanged even if the corresponding source properties use 'Id'.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1716
File: web-devtools/src/app/(main)/dispute-template/CustomContextInputs.tsx:29-42
Timestamp: 2024-10-28T05:55:12.728Z
Learning: In the `CustomContextInputs` component located at `web-devtools/src/app/(main)/dispute-template/CustomContextInputs.tsx`, the `DisputeRequestParams` array is used to exclude certain variables from the custom input since they are already provided in a preceding component. Therefore, converting it to a type is unnecessary.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: web/src/hooks/queries/usePopulatedDisputeData.ts:58-61
Timestamp: 2024-10-14T13:58:25.708Z
Learning: In `web/src/hooks/queries/usePopulatedDisputeData.ts`, the query and subsequent logic only execute when `disputeData.dispute?.arbitrableChainId` and `disputeData.dispute?.externalDisputeId` are defined, so `initialContext` properties based on these values are safe to use without additional null checks.
contracts/test/arbitration/dispute-kit-gated.ts (2)
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: web/src/hooks/queries/usePopulatedDisputeData.ts:58-61
Timestamp: 2024-10-14T13:58:25.708Z
Learning: In `web/src/hooks/queries/usePopulatedDisputeData.ts`, the query and subsequent logic only execute when `disputeData.dispute?.arbitrableChainId` and `disputeData.dispute?.externalDisputeId` are defined, so `initialContext` properties based on these values are safe to use without additional null checks.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1744
File: web/src/hooks/useGenesisBlock.ts:9-31
Timestamp: 2024-11-19T05:31:48.701Z
Learning: In `useGenesisBlock.ts`, within the `useEffect` hook, the conditions (`isKlerosUniversity`, `isKlerosNeo`, `isTestnetDeployment`) are mutually exclusive, so multiple imports won't execute simultaneously, and race conditions are not a concern.
🧬 Code Graph Analysis (2)
contracts/deploy/utils/deployTokens.ts (1)
contracts/deploy/utils/getContractOrDeploy.ts (1)
  • getContractOrDeploy (6-20)
contracts/test/arbitration/dispute-kit-gated.ts (3)
contracts/deploy/utils/index.ts (1)
  • PNK (40-40)
contracts/deployments/utils.ts (1)
  • deployments (3-16)
contracts/deploy/utils/deployTokens.ts (2)
  • deployERC721 (55-67)
  • deployERC1155 (69-81)
⏰ 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). (6)
  • GitHub Check: SonarCloud
  • GitHub Check: Analyze (javascript)
  • GitHub Check: contracts-testing
  • GitHub Check: SonarCloud
  • GitHub Check: Analyze (javascript)
  • GitHub Check: contracts-testing
🔇 Additional comments (6)
contracts/deploy/00-home-chain-arbitration.ts (1)

99-123: Add validation and dynamic retrieval of dispute kit IDs

Hardcoding dispute kit IDs (2, 3, 4) assumes a fixed deployment order and that DisputeKitClassic is always ID 1. If deployments shift or fail, these IDs may become invalid.

• Confirm that the KlerosCore contract emits a DisputeKitCreated event (or equivalent) returning the new kit ID.
• Ensure addNewDisputeKit either returns the new ID directly or emits an event you can decode.
• If so, replace hardcoded IDs with the value extracted from the transaction receipt before calling enableDisputeKits.

Suggested pattern:

-  await core.addNewDisputeKit(disputeKitShutter.address);
-  await core.enableDisputeKits(Courts.GENERAL, [2], true);
+  const tx = await core.addNewDisputeKit(disputeKitShutter.address);
+  const receipt = await tx.wait();
+  // TODO: adjust log decoding to match the actual event signature
+  const event = receipt.logs.find((log: any) =>
+    log.topics?.[0] === core.interface.getEventTopic("DisputeKitCreated")
+  );
+  const disputeKitShutterId = core.interface.decodeEventLog(
+    "DisputeKitCreated",
+    event.data,
+    event.topics
+  )._disputeKitID;
+  await core.enableDisputeKits(Courts.GENERAL, [disputeKitShutterId], true);

Please verify that the KlerosCore contract actually emits DisputeKitCreated (or similar) with the new dispute kit ID, and adjust the decoding logic accordingly.

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

44-44: Correct use of reinitializer for contract upgrade.

The change from initializer to reinitializer(1) is appropriate for upgradeable contracts that need new initialization logic after deployment.


90-111: Correct implementation of dynamic token gating.

The function properly extracts token gating parameters from dispute-specific extraData and validates juror eligibility based on token balances. The permissive default behavior when no token gate is specified ensures backward compatibility.

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

90-99: Well-implemented shielded commit function.

The function correctly extends the base commit functionality with Shutter-specific encryption parameters and event emission.


126-133: Secure and efficient vote hashing implementation.

The function correctly hashes the justification separately before including it in the final hash, which is a good practice for both security and gas efficiency.


101-113: No additional access control needed for castVoteShutter

The Shutter-specific castVoteShutter intentionally derives the juror from storage and forwards it to _castVote, which already enforces:

  • The dispute is in the Vote period
  • Each voteID truly belongs to that juror (round.votes[i].account == _juror)
  • For hidden-votes courts, the supplied choice/salt/justification hash matches the stored commit
  • A vote cannot be cast twice (!round.votes[i].voted)

Because every reveal must satisfy those checks (including correct commit verification), opening castVoteShutter to third-party callers doesn’t let anyone forge or alter votes—only automate revealing already-committed votes. No changes are required.

process.env.ARB_GOERLI_PRIVATE_KEY_WALLET_5 as string,
]) ||
(process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : []),
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify deployment scripts compatibility with single account configuration.

The change from supporting multiple private keys to a single PRIVATE_KEY simplifies the configuration but could break existing deployment scripts that rely on multiple accounts. Ensure all deployment scripts and tasks are compatible with this change.

Also applies to: 126-126


🏁 Script executed:

#!/bin/bash
# Description: Check if any deployment scripts or tasks use multiple accounts

# Search for usage of multiple accounts or named accounts beyond deployer
rg -A 5 "getNamedAccounts|namedAccounts" --type ts --type js

# Search for array access patterns on accounts that might break
rg "accounts\[(?!0\])" --type ts --type js

# Check for references to the removed environment variables
rg "ARBITRUM_SEPOLIA_PRIVATE_KEY|GNOSIS_CHIADO_PRIVATE_KEY" --type ts --type js

Length of output: 27218


Adjust relayer named account for single‐key setup

The switch to a single PRIVATE_KEY means only one account (index 0) is provided, but namedAccounts.rel​ayer still defaults to index 1. Any call to await getNamedAccounts() that destructures { relayer } will now fail.

Please update the config and code:

• In contracts/hardhat.config.ts
– Change
diff namedAccounts: { deployer: { default: 0 }, - relayer: { default: 1 }, + relayer: { default: 0 }, // … }

• In tests/scripts that expect a second signer:
– contracts/test/integration/draw.ts
– contracts/test/arbitration/draw.ts
– (and any other files doing ({ deployer, relayer } = await getNamedAccounts()))

• Documentation:
– Note that only one key is supported, or introduce a second env var for relayer if you need multiple accounts.

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

🤖 Prompt for AI Agents
In contracts/hardhat.config.ts at line 108, the relayer named account is set to
index 1 by default, but with a single PRIVATE_KEY only index 0 is available.
Update the namedAccounts configuration to set relayer to index 0 instead of 1.
Also, review and update any test or script files like
contracts/test/integration/draw.ts and contracts/test/arbitration/draw.ts that
destructure relayer from getNamedAccounts to align with this single-key setup.
Finally, update documentation to clarify that only one key is supported or add
instructions for adding a second key if needed.

Comment on lines +69 to +81
export const deployERC1155 = async (
hre: HardhatRuntimeEnvironment,
deployer: string,
name: string,
ticker: string
): Promise<Contract> => {
return getContractOrDeploy(hre, ticker, {
from: deployer,
contract: "TestERC1155",
args: [],
log: true,
});
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused name parameter from deployERC1155 function.

The name parameter is not used in the function body since TestERC1155 constructor takes no arguments. This creates an inconsistent API compared to deployERC721 which uses both parameters.

-export const deployERC1155 = async (
-  hre: HardhatRuntimeEnvironment,
-  deployer: string,
-  name: string,
-  ticker: string
-): Promise<Contract> => {
+export const deployERC1155 = async (
+  hre: HardhatRuntimeEnvironment,
+  deployer: string,
+  ticker: string
+): Promise<Contract> => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const deployERC1155 = async (
hre: HardhatRuntimeEnvironment,
deployer: string,
name: string,
ticker: string
): Promise<Contract> => {
return getContractOrDeploy(hre, ticker, {
from: deployer,
contract: "TestERC1155",
args: [],
log: true,
});
};
export const deployERC1155 = async (
hre: HardhatRuntimeEnvironment,
deployer: string,
ticker: string
): Promise<Contract> => {
return getContractOrDeploy(hre, ticker, {
from: deployer,
contract: "TestERC1155",
args: [],
log: true,
});
};
🤖 Prompt for AI Agents
In contracts/deploy/utils/deployTokens.ts around lines 69 to 81, the
deployERC1155 function includes an unused parameter 'name'. Remove the 'name'
parameter from the function signature to keep the API consistent and avoid
confusion, since it is not used in the function body or passed to the contract
constructor.

Comment on lines +36 to +38
function changeOwner(address _newOwner) external ownerOnly {
owner = _newOwner;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Emit event when ownership changes.

The changeOwner function should emit an event for transparency and off-chain tracking.

+event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

 function changeOwner(address _newOwner) external ownerOnly {
+    address previousOwner = owner;
     owner = _newOwner;
+    emit OwnershipTransferred(previousOwner, _newOwner);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function changeOwner(address _newOwner) external ownerOnly {
owner = _newOwner;
}
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function changeOwner(address _newOwner) external ownerOnly {
address previousOwner = owner;
owner = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
🤖 Prompt for AI Agents
In contracts/src/token/TestERC1155.sol around lines 36 to 38, the changeOwner
function updates the owner but does not emit an event. Define an
OwnershipChanged event if not already present, and emit this event inside the
changeOwner function after updating the owner, passing the old and new owner
addresses to enable transparency and off-chain tracking.

// ************************************* //

address public owner;
uint256 private _nextTokenId;
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

Remove unused _nextTokenId variable.

The _nextTokenId state variable is declared but never used in the contract.

     address public owner;
-    uint256 private _nextTokenId;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uint256 private _nextTokenId;
address public owner;
🤖 Prompt for AI Agents
In contracts/src/token/TestERC1155.sol at line 13, the state variable
_nextTokenId is declared but not used anywhere in the contract. Remove the
declaration of the _nextTokenId variable to clean up unused code and avoid
unnecessary state storage.

await deployERC721(hre, deployer, "TestERC721", "Nft721");
nft721 = (await ethers.getContract("Nft721")) as TestERC721;

await deployERC1155(hre, deployer, "TestERC1155", "Nft1155");
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

Update deployERC1155 call to match the function signature.

Based on the suggested refactor in deployTokens.ts, the deployERC1155 function should only take 3 parameters (without the name parameter).

-    await deployERC1155(hre, deployer, "TestERC1155", "Nft1155");
+    await deployERC1155(hre, deployer, "Nft1155");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await deployERC1155(hre, deployer, "TestERC1155", "Nft1155");
await deployERC1155(hre, deployer, "Nft1155");
🤖 Prompt for AI Agents
In contracts/test/arbitration/dispute-kit-gated.ts at line 70, the call to
deployERC1155 currently passes three arguments including a name parameter, but
the updated deployERC1155 function signature accepts only three parameters
without the name. Remove the name argument from the call so that deployERC1155
is called with only hre, deployer, and the contract identifier string.

let nft721: TestERC721;
let nft1155: TestERC1155;
const RANDOM = 424242n;
const GATED_DK_ID = 3;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid hardcoding dispute kit ID.

The hardcoded GATED_DK_ID = 3 assumes a specific deployment order which could break if deployment changes.

Consider retrieving the dispute kit ID dynamically:

-  const GATED_DK_ID = 3;
+  let GATED_DK_ID: number;
+  
+  beforeEach("Setup", async () => {
+    // ... existing setup code ...
+    
+    // Get the actual dispute kit ID from the contract
+    const disputeKitCount = await core.disputeKitIDCount();
+    // DisputeKitGated should be the 3rd kit (after Classic and Shutter)
+    GATED_DK_ID = Number(disputeKitCount) - 2;

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

🤖 Prompt for AI Agents
In contracts/test/arbitration/dispute-kit-gated.ts at line 38, avoid hardcoding
the dispute kit ID as 3 because it assumes a fixed deployment order. Instead,
modify the code to retrieve the dispute kit ID dynamically from the deployed
contracts or configuration, ensuring it adapts to changes in deployment order or
environment.

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

🔭 Outside diff range comments (2)
contracts/deployments/arbitrumSepoliaDevnet/KlerosCore.json (2)

1839-1843: setStakeBySortitionModule parameter removed – verify module upgrade

The _alreadyTransferred flag is gone. Older sortition-module bytecode will fail to compile / call the new signature, bricking stake updates. Make sure the sortition module was upgraded in the same migration and that all chains use the matching binary.


825-866: Duplicate arbitrationCost overload – potential front-end ambiguity

There are two arbitrationCost functions (with and without _feeToken).
Web3 libraries that don’t auto-disambiguate (e.g. ethers v5’s contract.arbitrationCost(...)) will pick the first match and may revert.

Recommend renaming one to arbitrationCostWithToken or similar, or at minimum documenting the exact signature to use (abi.encodeWithSignature).

🧹 Nitpick comments (7)
contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler.json (1)

1512-1524: Redundant public version() function – consider exposing the constant via public constant instead.

Solidity automatically generates an external getter for a public constant string version = "...";.
Maintaining both the state variable and an explicit version() duplicates byte-code and increases gas costs for deployment/upgrade.

If the implementation already contains string public constant version = "x.y.z", you can safely drop the explicit function.

contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassic.json (3)

324-352: Consider using a more explicit view name

alreadyDrawn(...) is useful, but the absence of an is*/has* prefix (isJurorAlreadyDrawn / hasBeenDrawn) makes its boolean return value less obvious for integrators scanning the ABI. A tiny rename would enhance self-descriptiveness and stay consistent with isAppealFunded, isVoteActive, etc.


757-804: Gas-heavy helper views – document usage expectations

getLocalDisputeRoundID and getNumberOfRounds walk internal arrays; on-chain callers (keeper bots, subgraph handlers through eth_call) could hit BLOCK_GAS_LIMIT for very large disputes.
It’s probably acceptable, but worth documenting limits in the NatSpec so external integrators don’t rely on them inside transactions.


916-944: Expose hash salt size in NatSpec

hashVote(uint256 _choice, uint256 _salt, string _justification) is handy for clients, but without comments developers don’t know the expected bit-width / entropy of _salt (e.g. full 256-bits vs 32-bits). Adding a brief note in the contract docstring prevents mismatched hashing across SDKs.

contracts/deployments/arbitrumSepoliaDevnet/KlerosCore.json (1)

1682-1687: Leftover initialize5()

Similar to the dispute-kit proxy, initialize5() is still in the ABI although the proxy calls initialize(...). Remove or make it internal to avoid accidental invocation through a direct delegatecall.

contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Implementation.json (1)

266-270: Version string drift

Inside the embedded source (version = "0.8.0"), the semantic “implementation version” has not changed, yet the contract was re-compiled with solc 0.8.28.
This may confuse auditors tooling that rely on the constant.

Consider bumping the constant (e.g. "0.8.1") or adopting calendar versions to signal that a new binary is live even when storage layout is unchanged.

contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Proxy.json (1)

29-36: Gas delta observation

Deployment used 175 490 gas (prev build ~173 k). The small increase is expected with 0.8.28 byte-op ordering changes. No action needed, just noting for gas regression tracking.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6e535cc and e2e6412.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (31)
  • contracts/DEVNET_REDEPLOY.md (1 hunks)
  • contracts/README.md (3 hunks)
  • contracts/README.md.template (2 hunks)
  • contracts/deploy/00-home-chain-arbitration.ts (3 hunks)
  • contracts/deploy/00-home-chain-resolver.ts (2 hunks)
  • contracts/deploy/upgrade-all.ts (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassic.json (7 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassic_Proxy.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGated.json (1 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGatedShutter.json (1 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGatedShutter_Proxy.json (1 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGated_Proxy.json (1 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter.json (1 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter_Proxy.json (1 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeResolver.json (6 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeResolverRuler.json (6 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistry.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistry_Implementation.json (3 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistry_Proxy.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule_Implementation.json (3 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule_Proxy.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCore.json (5 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler.json (5 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler_Proxy.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreSnapshotProxy.json (4 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCore_Proxy.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Implementation.json (3 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Proxy.json (2 hunks)
  • contracts/deployments/arbitrumSepoliaDevnet/SortitionModule.json (12 hunks)
✅ Files skipped from review due to trivial changes (16)
  • contracts/DEVNET_REDEPLOY.md
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreSnapshotProxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCore_Proxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGatedShutter_Proxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler_Proxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule_Implementation.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassic_Proxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGated_Proxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeResolverRuler.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistry_Proxy.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeResolver.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistry.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistry_Implementation.json
  • contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGated.json
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitGatedShutter.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • contracts/deploy/upgrade-all.ts
  • contracts/README.md
  • contracts/deploy/00-home-chain-arbitration.ts
  • contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter_Proxy.json
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
Learnt from: kemuru
PR: kleros/kleros-v2#1702
File: web/src/pages/Home/TopJurors/JurorCard/index.tsx:10-11
Timestamp: 2024-10-07T06:18:23.427Z
Learning: In the `kleros-v2` codebase, the property `totalResolvedDisputes` should remain and should not be renamed to `totalResolvedVotes`.
Learnt from: kemuru
PR: kleros/kleros-v2#1702
File: web/src/pages/Home/TopJurors/JurorCard/index.tsx:10-11
Timestamp: 2024-10-08T16:23:56.291Z
Learning: In the `kleros-v2` codebase, the property `totalResolvedDisputes` should remain and should not be renamed to `totalResolvedVotes`.
contracts/README.md.template (2)
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-17
Timestamp: 2024-11-19T16:09:41.467Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (ID: 1) can have its `parent` ID set to itself (`"parent": 1`), as there is no parent court with ID 0 currently.
contracts/deploy/00-home-chain-resolver.ts (3)
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: web/src/hooks/queries/usePopulatedDisputeData.ts:58-61
Timestamp: 2024-10-14T13:58:25.708Z
Learning: In `web/src/hooks/queries/usePopulatedDisputeData.ts`, the query and subsequent logic only execute when `disputeData.dispute?.arbitrableChainId` and `disputeData.dispute?.externalDisputeId` are defined, so `initialContext` properties based on these values are safe to use without additional null checks.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1647
File: web/src/context/NewDisputeContext.tsx:0-0
Timestamp: 2024-10-08T16:23:56.290Z
Learning: The `delete` operator is used in the `constructDisputeTemplate` function in `web/src/context/NewDisputeContext.tsx` to remove the `policyURI` field if it is an empty string.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1647
File: web/src/context/NewDisputeContext.tsx:0-0
Timestamp: 2024-07-25T11:58:27.058Z
Learning: The `delete` operator is used in the `constructDisputeTemplate` function in `web/src/context/NewDisputeContext.tsx` to remove the `policyURI` field if it is an empty string.
contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Implementation.json (3)
Learnt from: jaybuidl
PR: kleros/kleros-v2#1805
File: contracts/src/proxy/UUPSProxiable.sol:127-129
Timestamp: 2025-01-22T00:55:35.842Z
Learning: In Solidity, a public state variable automatically implements a corresponding external view function with the same name. For example, `string public constant override version = "0.8.0"` implements the abstract `function version() external view returns (string memory)`.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-17
Timestamp: 2024-11-19T16:09:41.467Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (ID: 1) can have its `parent` ID set to itself (`"parent": 1`), as there is no parent court with ID 0 currently.
contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassic.json (2)
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: web/src/hooks/queries/usePopulatedDisputeData.ts:58-61
Timestamp: 2024-10-14T13:58:25.708Z
Learning: In `web/src/hooks/queries/usePopulatedDisputeData.ts`, the query and subsequent logic only execute when `disputeData.dispute?.arbitrableChainId` and `disputeData.dispute?.externalDisputeId` are defined, so `initialContext` properties based on these values are safe to use without additional null checks.
Learnt from: Harman-singh-waraich
PR: kleros/kleros-v2#1703
File: kleros-sdk/src/utils/getDispute.ts:38-40
Timestamp: 2024-10-21T10:32:16.970Z
Learning: The variables 'arbitrableChainID' and 'externalDisputeID' are required by the context to have uppercase 'ID', so they should remain unchanged even if the corresponding source properties use 'Id'.
contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler.json (1)
Learnt from: jaybuidl
PR: kleros/kleros-v2#1805
File: contracts/src/proxy/UUPSProxiable.sol:127-129
Timestamp: 2025-01-22T00:55:35.842Z
Learning: In Solidity, a public state variable automatically implements a corresponding external view function with the same name. For example, `string public constant override version = "0.8.0"` implements the abstract `function version() external view returns (string memory)`.
contracts/deployments/arbitrumSepoliaDevnet/KlerosCore.json (1)
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.
contracts/deployments/arbitrumSepoliaDevnet/SortitionModule.json (3)
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.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-17
Timestamp: 2024-11-19T16:09:41.467Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (ID: 1) can have its `parent` ID set to itself (`"parent": 1`), as there is no parent court with ID 0 currently.
Learnt from: jaybuidl
PR: kleros/kleros-v2#1746
File: contracts/config/courts.v2.mainnet-neo.json:3-5
Timestamp: 2024-11-19T17:18:39.007Z
Learning: In `contracts/config/courts.v2.mainnet-neo.json`, the General Court (id: 1) intentionally references itself as its parent (`"parent": 1`). This self-reference is acceptable and should not be flagged as an issue in future reviews.
⏰ 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). (4)
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Mend Security Check
🔇 Additional comments (20)
contracts/README.md.template (3)

92-92: LGTM! Deployment tag update aligns with code changes.

The tag change from "HomeArbitrable" to "Resolver" is consistent with the deployment script changes in 00-home-chain-resolver.ts.


154-154: Documentation section title updated appropriately.

The section title change from "Local Network" to "Public Testnet" accurately reflects the removal of local network import instructions and focus on testnet deployment.


157-158: Commands updated to use Hardhat tasks with proper parameters.

The migration from script-based commands to Hardhat tasks (populate:courts and populate:policy-registry) with specific parameters like --from v2_testnet and --max-number-of-courts 3 provides better control and configurability for testnet deployments.

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

16-16: LGTM! Correctly reuses existing DisputeTemplateRegistry deployment.

The change from deploying a new DisputeTemplateRegistry to retrieving an existing deployment is appropriate and aligns with the modular deployment approach mentioned in the PR objectives.


25-25: Deployment tag updated consistently.

The tag change from "HomeArbitrable" to "Resolver" is consistent with the documentation updates and suggests better organization of deployment responsibilities.

contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler.json (2)

1591-1593: Compiler version mismatch between metadata (0.8.28) and pragma (0.8.24) in KlerosProxies.sol.

metadata.compiler.version shows 0.8.28, but the embedded source in the same metadata declares pragma solidity ^0.8.24;.
Although compatible, this can trip verification tools and lead to opaque-bytecode warnings on explorers.

Make sure the source tree is re-compiled with the exact declared pragma (or update the pragma to ^0.8.28) before publishing to Etherscan/blockscout.


1607-1607: Implementation address updated – remember to add a proxy admin acceptance script.

The deployment now points proxy to 0xb8bF3A3…. Confirm that:

  1. The upgradeTo transaction was executed by the proxy admin.
  2. The admin has run acceptUpgrade() (if applicable in your upgrade framework).

Skipping this step will leave the proxy in an inconsistent state.

contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassic.json (2)

486-504: Confirm no storage/ABI clash with the public mapping

coreDisputeIDToActive(uint256) appears as a regular view function yet its name suggests an automatically-generated getter for a public mapping.
If this is the mapping getter (declared mapping(uint => bool) public coreDisputeIDToActive;) everything is fine.
If, however, the contract keeps a private mapping and added a manual function with the same name, the Solidity compiler will create two selectors and the proxy will expose only one, silently shadowing the other. Please double-check the solidity source.


964-969: Redundant initialize7() still present

The proxy executes initialize(address,address) but the ABI also exposes a legacy initialize7() (no inputs). Leaving deprecated initializers callable (even if OZ’s onlyInitializing guard keeps them inert) increases surface area for griefing attacks and confuses integrators. If the function is no longer needed, consider removing it in the implementation contract before deploying the next version.

contracts/deployments/arbitrumSepoliaDevnet/KlerosCore.json (2)

1330-1336: Breaking change: draw() now returns uint256 nbDrawnJurors

Previous releases returned the drawn address (or nothing). Any downstream code—or third-party bots—expecting the old signature will now decode the return data incorrectly and revert.

Please ensure:

  1. All in-repo calls (keeperBot, subgraph mapping handlers, front-end hooks) were updated.
  2. External docs / README mention the new return value.

Consider emitting a DrawIterations(uint256 disputeId,uint256 nbDrawn) event for off-chain consumers instead of relying on the return value of a state-changing tx.


1857-1874: Access-control audit for transferBySortitionModule

A direct token transfer helper is handy, but it must be strictly onlySortitionModule.
Double-check the Solidity modifier; even a mis-ordering with OZ’s onlyRole could let an attacker siphon PNK.
Also ensure re-entrancy guards (nonReentrant) are in place if arbitrary _account callbacks are possible (e.g. ERC-777 hooks).

contracts/deployments/arbitrumSepoliaDevnet/SortitionModule.json (2)

345-376: alreadyTransferred flag appears to be a leftover

The description of this refactor (and the related Solidity diff) states that delayed–stake flags/mappings were removed, yet the ABI for delayedStakes still exposes the alreadyTransferred : bool field.
If the implementation really dropped that storage member, this ABI entry is stale and external indexers / TS typings generated from it will decode wrong offsets.

Please double-check the implementation vs. the generated artifact and regenerate the ABI if the flag is indeed gone.


409-416: Return type mismatch with newly-documented behaviour?

draw(bytes32,uint256,uint256) here still returns (address drawnAddress) and is marked view, while the PR description highlights that KlerosCoreBase.draw() now returns “number of jurors drawn”.
If any off-chain tooling now relies on the updated interface but points to the SortitionModule ABI, calls will revert or mis-decode.

Confirm that:

  1. Front-end & keeper bot call the correct contract (KlerosCore vs SortitionModule).
  2. No generated client code uses this ABI for the new return signature.

A quick grep against the web & scripts packages is advisable.

contracts/deployments/arbitrumSepoliaDevnet/DisputeKitShutter.json (1)

1067-1072: Public initialize8 still present – ensure it’s gated

Having successive public/nonpayable initialisers (initialize, initialize8) is OK for UUPS upgrades but only if they are protected by reinitializer(x) modifiers that block multiple invocations.
Double-check that DisputeKitShutter’s Solidity contract marks initialize8 with the appropriate OpenZeppelin reinitializer guard and that the version number is higher than any prior initialiser to avoid accidental re-initialisation.

contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry.json (1)

254-262: Deployment metadata only – looks fine

Proxy address, implementation address and compiler metadata were bumped. No ABI changes detected, so downstream integrations stay intact.

contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Implementation.json (2)

2-2: Confirm upgrade path & env-reference update

The implementation address has been bumped to 0x4728…5deD.
Please double-check that:

  1. Every proxy (both on–chain and in the deployment scripts / .env) now points to this new address.
  2. Front-end or subgraph configs do not cache the previous address.

A mismatched proxy ↔ implementation pairing will brick upgrades and break reads.


381-395: Storage layout unchanged – good

Only governor (slot 0) and policies (slot 1) remain. No layout deltas → upgrade safe.

contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Proxy.json (1)

2-2: Proxy redeployed – implementation arg sanity

New proxy at 0xd868…75e8A.

Ensure the constructor arg (_implementation) equals the fresh PolicyRegistry implementation (0x4728…5deD) – line 59 shows it does, 🚀.

contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule_Proxy.json (2)

2-2: New EvidenceModule proxy address propagation

Proxy moved to 0xA1F7…0B49. Make sure:

  • Court/Dispute resolver contracts that cache the EvidenceModule address are updated.
  • Subgraph & FE env vars reference the new proxy.

Forgetting to propagate will yield “call to non-contract” at runtime.


59-60: Constructor arg points to fresh implementation

The first arg now 0x450A…2200 (new EvidenceModule impl). Looks consistent with the redeploy batch – good catch.

Comment on lines +1379 to +1385
{
"inputs": [],
"name": "initialize2",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
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

initialize2() exposes a second, zero-arg initializer – confirm it is protected by reinitializer(2) or equivalent.

Having a follow-up initializer on an upgradeable contract is fine only if:

  1. The implementation uses OpenZeppelin’s reinitializer(version) (or similar custom guard) so the function can be executed exactly once, and
  2. Only the proxy admin (or an authorised governor) can call it.

Because the ABI alone does not show modifiers, please double-check the Solidity code:

  • initialize2 must carry reinitializer(2) (or higher) rather than initializer.
  • It must not be public/external without an explicit access-control modifier.

If either guard is missing, attackers could re-initialise state and seize control or drain funds.

🤖 Prompt for AI Agents
In contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreRuler.json around lines
1379 to 1385, the initialize2() function is defined without visible access
control or reinitializer protection in the ABI. Review the corresponding
Solidity source code to ensure initialize2() is marked with the reinitializer(2)
modifier (or equivalent) to allow a single execution and verify it has proper
access control restricting calls to only the proxy admin or authorized governor.
If these protections are missing, add the reinitializer(2) modifier and
appropriate access control modifiers to prevent unauthorized re-initialization.

Copy link

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.

5 participants