Documentation Index
Fetch the complete documentation index at: https://kleros-mintlify-changelog-2026-05-12-1778458371.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Before You Deploy
Use this checklist before deploying to mainnet. Each item has bitten someone before.Smart Contract Security
Access Control
-
rule()only callable by arbitrator - Dispute creation restricted to valid parties
- Evidence submission restricted appropriately
- Admin functions protected (if any)
State Management
- Disputes cannot be ruled twice
- Invalid ruling values rejected
- Ruling
0(refuse to arbitrate) handled explicitly - All state transitions are valid (no skipping states)
Reentrancy Protection
- State updated before external calls in
rule() - Use checks-effects-interactions pattern
- Consider
ReentrancyGuardfor complex logic
Fund Safety
- No funds can be permanently locked
- Failed transfers don’t brick the contract
- Consider pull-over-push for withdrawals
- Test with contracts as recipients (not just EOAs)
Arbitration Configuration
Court Selection
| Check | Status |
|---|---|
| Court ID exists on target network | ▢ |
| Court handles your dispute type | ▢ |
| Minimum stake is acceptable | ▢ |
| Court timing fits your use case | ▢ |
| Court ID | Name | Typical Use |
|---|---|---|
| 1 | General Court | Default for most disputes. Good starting point. |
| 2 | Blockchain | Technical blockchain/smart contract disputes |
| 3 | Non-Technical | Business, marketing, and content disputes |
| 4 | Token Listing | Token curation and listing decisions |
| 5+ | Specialized | Check court.kleros.io for the current tree |
courts(courtID) getter on KlerosCore rather than hardcoding.
Extra Data
-
extraDatacorrectly encodes court ID and juror count - Juror count is odd (avoids ties)
- Juror count appropriate for dispute value
Fee Handling
- Always fetch fresh
arbitrationCost()before creating dispute - Handle fee increases between check and execution
- Refund excess fees to sender
- Document who pays arbitration fees
- If paying in ERC20: verify the token is in
acceptedFeeTokenson KlerosCore - If paying in ERC20: call
arbitrationCost(extraData, feeToken)(not the ETH overload) - If paying in ERC20: approve KlerosCore to spend the fee amount before
createDispute() - Account for appeal costs each appeal round roughly doubles the juror count and cost
- For cross-chain disputes: the Foreign Gateway mirrors
arbitrationCost()locally, but sync may lag after governance changes add a buffer or retry mechanism
Dispute Template
Content Quality
- Question is clear and unambiguous
- All ruling options are mutually exclusive
- Ruling descriptions explain consequences
- No option can be interpreted multiple ways
- “Refuse to arbitrate” scenario documented
Technical
- Template JSON is valid
- Template stored on permanent storage (IPFS pinned / Arweave)
- Template URI accessible and resolves correctly
-
policyURIpoints to valid policy document -
arbitratorAddressmatches deployment -
arbitratorChainIDmatches deployment
Example Template Validation
Policy Document
Every dispute should reference a policy document that jurors use to make decisions. This is distinct from the template the template defines the UI; the policy defines the rules.- Policy document clearly states criteria for each ruling option
- Policy covers edge cases (partial fulfillment, ambiguous evidence)
- Policy states what happens on “Refuse to Arbitrate” (ruling 0)
- Policy is written for a non-technical audience (jurors are general public)
- Policy is hosted on pinned IPFS or Arweave (not a URL that can change)
- Policy has been reviewed for ambiguity by someone unfamiliar with your protocol
Dispute Lifecycle Timing
Kleros disputes follow a fixed phase sequence. Understand the timing impact on your application:| Phase | Duration (General Court) | Notes |
|---|---|---|
| Evidence | ~3 days | Either party can submit evidence |
| Voting | ~3 days | Jurors cast encrypted votes (Shutter) |
| Appeal | ~5 days | Losing party can fund an appeal |
| Total (no appeal) | ~11 days | Minimum time to ruling |
| Per appeal round | +~11 days | Each round adds roughly the same |
- Your application tolerates the dispute resolution timeline (1–4 weeks typical)
- Funds or state remain locked during the dispute without creating issues
- Users are informed about expected timelines in your UI
- You handle the case where appeals extend the timeline significantly
Events & Indexing
-
DisputeRequestemitted with correct parameters -
Rulingemitted after executing ruling -
Evidenceevents use correctevidenceGroupID - Events are indexed for efficient querying
- Subgraph indexes your contract (if using one)
Gas Optimization
Benchmarks
| Function | Target | Your Contract |
|---|---|---|
createDispute() | < 200k gas | ▢ |
rule() | < 100k gas | ▢ |
submitEvidence() | < 50k gas | ▢ |
Optimizations Applied
- Use
immutablefor arbitrator address - Pack structs efficiently
- Avoid redundant storage reads
- Use
calldatainstead ofmemorywhere possible
Deployment
Contract Verification
- Source code verified on block explorer
- Constructor arguments documented
- All dependencies verified
- License specified in source
Address Verification
| Contract | Expected | Deployed |
|---|---|---|
| KlerosCore | 0x33d0b8879... | ▢ Match |
| Your Arbitrable | — | ▢ Verified |
| Dispute Template | — | ▢ Accessible |
Initialization
- Arbitrator address is correct for network
- Extra data encodes correct court
- Template URI resolves correctly
- Any admin roles assigned correctly
- Contract funded if required
Operational Readiness
Monitoring
- Alert on
DisputeRequestevents - Alert on
Rulingevents - Monitor arbitration fee changes
- Track dispute resolution times
- Dashboard for active disputes
- Monitor
AppealDecisionevents from KlerosCore appeals change timeline and cost - Subscribe to court parameter changes via
CourtModifiedevents fee changes affect your cost calculations - Track your disputes on court.kleros.io filter by your contract’s address
- If cross-chain: monitor Vea bridge claim/challenge status on veascan.io
- Set up alerts for the KlerosCore
Pausedevent a paused arbitrator blocks new disputes and rulings
Documentation
- User guide for creating disputes
- Evidence submission instructions
- Explanation of ruling outcomes
- FAQ for common questions
- Support contact for issues
Incident Response
- Plan for paused arbitrator scenario
- Plan for unexpected ruling
- Emergency contact at Kleros (if needed)
- Upgrade path documented (if upgradeable)
- Arbitrator paused: KlerosCore has an emergency pause mechanism controlled by the Guardian role. If paused, no new disputes can be created and no rulings can be delivered. Your contract should handle a
createDispute()revert gracefully and inform users. - Ruling 0 (Refuse to Arbitrate): This ruling means jurors found the dispute invalid. Your contract must handle this case explicitly do not treat it the same as any party winning.
- Tied vote: In the current DisputeKitClassic, a tied vote defaults to ruling 0 (refuse to arbitrate) unless overridden by appeal. Design your ruling-0 handler to produce a reasonable fallback (e.g., refund both parties).
- Contract address change: V2 contracts are upgradeable proxies. After security audits, addresses may be preserved but implementation changes. If you store the arbitrator address as
immutable, you cannot adapt consider using a governor-updatable address. - Vea bridge delay (cross-chain only): In the unhappy path, ruling delivery can take ~7 days via the native Arbitrum bridge. Ensure your locked state can persist for at least 2 weeks without causing user issues.
Kleros V2 on Mainnet
Kleros V2 (Neo) is live on Arbitrum One mainnet. Court access is open to all — users can stake PNK and participate as jurors. These items are still relevant for integrators:- Contract upgrades: V2 contracts use UUPS proxy patterns and may be upgraded via governance. Subscribe to the Kleros blog and Discord for announcements.
- Subgraph stability: Pin to a specific subgraph deployment version in production. Check the kleros-v2 subgraph README for the latest stable deployment IDs.
-
SDK status:
@kleros/kleros-sdkis under active development. For maximum stability, you can interact with contracts directly via ABIs from@kleros/kleros-v2-contracts. - Testnet first: Always deploy and test a full dispute lifecycle on Arbitrum Sepolia before mainnet. Testnet disputes may take longer to resolve due to limited juror participation.
Contact the Kleros team via Discord or
integrations@kleros.io before your first production deployment. The team can review your dispute template and advise on court selection.Final Sign-Off
| Review | Completed By | Date |
|---|---|---|
| Code review | ▢ | |
| Security audit | ▢ | |
| Testnet deployment | ▢ | |
| Testnet dispute test | ▢ | |
| Gas benchmarks | ▢ | |
| Documentation | ▢ |
Quick Reference
Mainnet Contract Addresses (Arbitrum One)
| Contract | Address |
|---|---|
| KlerosCore (proxy) | 0x33d0b8879368acD8ca868e656Ade97bBcfeB12BA |
| SortitionModule | Verify from deployments |
| DisputeKitClassic | Verify from deployments |
| DisputeTemplateRegistry | Verify from deployments |
| HomeGateway | Verify from deployments |
Useful Links
- Kleros Court UI Monitor disputes
- GitHub Deployments Contract addresses
- Kleros Discord Developer support
Common Last-Minute Issues
Wrong network addresses
Wrong network addresses
Double-check you’re not using testnet addresses on mainnet or vice versa. KlerosCore on Arbitrum Sepolia has a different address than on Arbitrum One.
Template not pinned
Template not pinned
IPFS content disappears if not pinned. Use Pinata, Infura, or Arweave for permanence. Kleros hosts a pinning service at
cdn.kleros.link but you should pin independently as well.Hardcoded fees
Hardcoded fees
Never hardcode arbitration fees. Always fetch dynamically. Fees change through governance and vary per court.
Missing refund logic
Missing refund logic
If user overpays arbitration fee, refund the excess.
Wrong extraData encoding
Wrong extraData encoding
V2 uses
abi.encodePacked(uint96(courtID), uint256(jurorCount)) note the uint96 for court ID, not uint256 as in V1. Using uint256 will encode a different court than intended.Odd vs even juror count
Odd vs even juror count
Always use an odd number of jurors (3, 5, 7) to avoid tied votes. Tied votes in DisputeKitClassic default to ruling 0 (refuse to arbitrate), which may not be what your users expect.
Dispute template not registered
Dispute template not registered
If using
templateId, make sure setDisputeTemplate() was called on the DisputeTemplateRegistry and you stored the returned templateId. If the ID is wrong, the Court UI won’t display your dispute correctly and jurors will see missing context.