-
Notifications
You must be signed in to change notification settings - Fork 48
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
base: master
Are you sure you want to change the base?
Conversation
…cting an internal function
…ata sources not deployed e.g. DisputeKitShutter on testnet
…or-multiple-dispute-kit-above-id-1
…ple-dispute-kit-above-id-1 feat: subgraph support for shutter disputekit in devnet
Shutterized Dispute Kit
} 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
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored
fix(kleros-app): add-state-for-confirm-email
} 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
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored Low
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored Low
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored Low
} catch (error) { | ||
throw new Error(`Failed to parse API response as JSON: ${responseText}`); | ||
} |
Check notice
Code scanning / SonarCloud
Exceptions should not be ignored Low
There was a problem hiding this 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 patternsThe catch block that rethrows the error is intentional and follows the codebase error handling patterns.
129-131
: Exception handling follows codebase patternsThe 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:
- ✅ Active dispute tracking (implemented)
- ❌ Explicit
deactivateDispute
function withonlyByCore
modifier (missing)- ❌ 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/apiweb/.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/apiweb/.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/apiThe 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 beforeREACT_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:
- Missing blank line at end of file
- 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 beforeREACT_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 globalBigInt
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) androundID
(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")
andincludes("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 fieldThe 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 generationThe code uses
crypto.getRandomValues
which is a Web Crypto API. For better Node.js compatibility, consider usingcrypto.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 valueThe 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 } };
<> | ||
{isClassicDisputeKit && ( | ||
<Classic isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} /> | ||
)} | ||
{isShutterDisputeKit && ( | ||
<Shutter isAppealMiniGuideOpen={isAppealMiniGuideOpen} toggleAppealMiniGuide={toggleAppealMiniGuide} /> | ||
)} | ||
</> | ||
) : ( |
There was a problem hiding this comment.
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.
<> | |
{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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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"]); |
There was a problem hiding this comment.
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.
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.
BigInt(parsedStoredData?.choice ?? 0), | ||
BigInt(parsedStoredData?.salt ?? 0), | ||
parsedStoredData?.justification ?? "", |
There was a problem hiding this comment.
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.
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.
eventHandlers: | ||
- event: StakeLocked(indexed address,uint256,bool) | ||
handler: handleStakeLocked | ||
- event: StakeSet(indexed address,uint256,uint256,uint256) | ||
handler: handleStakeSet | ||
file: ./src/SortitionModule.ts |
There was a problem hiding this comment.
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.
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.
# 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" | ||
|
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
for i in "${notDeployedSourceIndices[@]}"; do | ||
echo -e "\e[1;31mDeleting data source $i\e[0m" | ||
yq -i 'del(.dataSources['$i'])' "$subgraphConfig" | ||
done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
There was a problem hiding this 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
📒 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 exceedstakedPnk
.
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.
Universal Gated Dispute Kit and Shutter Gated Dispute Kit
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
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
There was a problem hiding this 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
andIBalanceHolderERC1155
interfaces are duplicated fromDisputeKitGated.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
inDisputeKitGated.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 fromDisputeKitGated._postDrawCheck
.Consider creating a shared base contract (e.g.,
DisputeKitGatedBase
) that bothDisputeKitGated
andDisputeKitGatedShutter
can inherit from to avoid this duplication.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 IDsHardcoding 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 aDisputeKitCreated
event (or equivalent) returning the new kit ID.
• EnsureaddNewDisputeKit
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 callingenableDisputeKits
.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 emitsDisputeKitCreated
(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
toreinitializer(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 castVoteShutterThe 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] : [], |
There was a problem hiding this comment.
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.relayer
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.
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, | ||
}); | ||
}; |
There was a problem hiding this comment.
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.
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.
function changeOwner(address _newOwner) external ownerOnly { | ||
owner = _newOwner; | ||
} |
There was a problem hiding this comment.
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.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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; |
There was a problem hiding this comment.
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.
Devnet redeployment
There was a problem hiding this 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 upgradeThe
_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
: DuplicatearbitrationCost
overload – potential front-end ambiguityThere are two
arbitrationCost
functions (with and without_feeToken
).
Web3 libraries that don’t auto-disambiguate (e.g. ethers v5’scontract.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 publicversion()
function – consider exposing the constant viapublic constant
instead.Solidity automatically generates an external getter for a
public constant string version = "...";
.
Maintaining both the state variable and an explicitversion()
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 anis*/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 withisAppealFunded
,isVoteActive
, etc.
757-804
: Gas-heavy helper views – document usage expectations
getLocalDisputeRoundID
andgetNumberOfRounds
walk internal arrays; on-chain callers (keeper bots, subgraph handlers through eth_call) could hitBLOCK_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
: Leftoverinitialize5()
Similar to the dispute-kit proxy,
initialize5()
is still in the ABI although the proxy callsinitialize(...)
. Remove or make itinternal
to avoid accidental invocation through a directdelegatecall
.contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Implementation.json (1)
266-270
: Version string driftInside the embedded source (
version = "0.8.0"
), the semantic “implementation version” has not changed, yet the contract was re-compiled withsolc 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 observationDeployment 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
⛔ 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
andpopulate: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) inKlerosProxies.sol
.
metadata.compiler.version
shows0.8.28
, but the embedded source in the same metadata declarespragma 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:
- The
upgradeTo
transaction was executed by the proxy admin.- 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 (declaredmapping(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
: Redundantinitialize7()
still presentThe proxy executes
initialize(address,address)
but the ABI also exposes a legacyinitialize7()
(no inputs). Leaving deprecated initializers callable (even if OZ’sonlyInitializing
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 returnsuint256 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:
- All in-repo calls (
keeperBot
, subgraph mapping handlers, front-end hooks) were updated.- 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 fortransferBySortitionModule
A direct token transfer helper is handy, but it must be strictly
onlySortitionModule
.
Double-check the Solidity modifier; even a mis-ordering with OZ’sonlyRole
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 leftoverThe description of this refactor (and the related Solidity diff) states that delayed–stake flags/mappings were removed, yet the ABI for
delayedStakes
still exposes thealreadyTransferred : 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 markedview
, while the PR description highlights thatKlerosCoreBase.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:
- Front-end & keeper bot call the correct contract (
KlerosCore
vsSortitionModule
).- 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
: Publicinitialize8
still present – ensure it’s gatedHaving successive public/nonpayable initialisers (
initialize
,initialize8
) is OK for UUPS upgrades but only if they are protected byreinitializer(x)
modifiers that block multiple invocations.
Double-check thatDisputeKitShutter
’s Solidity contract marksinitialize8
with the appropriate OpenZeppelinreinitializer
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 fineProxy 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 updateThe implementation address has been bumped to
0x4728…5deD
.
Please double-check that:
- Every proxy (both on–chain and in the deployment scripts /
.env
) now points to this new address.- 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 – goodOnly
governor
(slot 0) andpolicies
(slot 1) remain. No layout deltas → upgrade safe.contracts/deployments/arbitrumSepoliaDevnet/PolicyRegistry_Proxy.json (1)
2-2
: Proxy redeployed – implementation arg sanityNew proxy at
0xd868…75e8A
.Ensure the constructor arg (
_implementation
) equals the freshPolicyRegistry
implementation (0x4728…5deD
) – line 59 shows it does, 🚀.contracts/deployments/arbitrumSepoliaDevnet/EvidenceModule_Proxy.json (2)
2-2
: New EvidenceModule proxy address propagationProxy 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 implementationThe first arg now
0x450A…2200
(new EvidenceModule impl). Looks consistent with the redeploy batch – good catch.
{ | ||
"inputs": [], | ||
"name": "initialize2", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
- The implementation uses OpenZeppelin’s
reinitializer(version)
(or similar custom guard) so the function can be executed exactly once, and - 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 carryreinitializer(2)
(or higher) rather thaninitializer
.- 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.
fix(web): blst error shutter v0.0.2
fix(subgraph): total-leaderboard-jurors-count
|
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
AllCasesButton
component.SeeAllCasesButton
andSeeAllJurorsButton
components.JustificationArea
import paths.disputeKit
to theStakingResult
enum.REACT_APP_SHUTTER_API
.disputeKit
structure.package.json
files.DisputeKitGatedShutterProxy
andDisputeKitShutterProxy
.Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores