> ## Documentation Index
> Fetch the complete documentation index at: https://kleros-mintlify-6ebc7975.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Production Checklist

> Pre-deployment security, arbitration, and access control checklist to verify your Kleros arbitrable contract before shipping to mainnet.

## 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
  ```solidity theme={null}
  require(msg.sender == address(arbitrator), "Only arbitrator");
  ```
* [ ] Dispute creation restricted to valid parties
* [ ] Evidence submission restricted appropriately
* [ ] Admin functions protected (if any)

### State Management

* [ ] Disputes cannot be ruled twice
  ```solidity theme={null}
  require(status == Status.Disputed, "Invalid state");
  status = Status.Resolved; // Update BEFORE external calls
  ```
* [ ] Invalid ruling values rejected
  ```solidity theme={null}
  require(_ruling <= numberOfChoices, "Invalid ruling");
  ```
* [ ] 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 `ReentrancyGuard` for complex logic
  ```solidity theme={null}
  // BAD: external call before state update
  payable(winner).transfer(amount);
  status = Status.Resolved;

  // GOOD: state update before external call  
  status = Status.Resolved;
  payable(winner).transfer(amount);
  ```

### 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   | ▢      |

**Kleros V2 Court IDs (Arbitrum One):**

| 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](https://court.kleros.io) for the current tree |

<Warning>
  Court IDs on Arbitrum Sepolia (testnet) differ from Arbitrum One (mainnet). Always verify IDs from the [kleros-v2 deployments](https://github.com/kleros/kleros-v2/tree/dev/contracts/deployments) for your target network.
</Warning>

Court parameters (minStake, feeForJuror, session timings) are governed and can change via governance proposals. Query them from the `courts(courtID)` getter on KlerosCore rather than hardcoding.

### Extra Data

* [ ] `extraData` correctly encodes court ID and juror count
  ```solidity theme={null}
  bytes memory extraData = abi.encodePacked(
      uint96(1),   // courtID
      uint256(3)   // minJurors
  );
  ```
* [ ] 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

**Kleros-specific fee details:**

* [ ] If paying in ERC20: verify the token is in `acceptedFeeTokens` on 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
* [ ] `policyURI` points to valid policy document
* [ ] `arbitratorAddress` matches deployment
* [ ] `arbitratorChainID` matches deployment

### Example Template Validation

```json theme={null}
{
  "title": "Clear, specific title",           // ✓ Not generic
  "description": "Full context...",           // ✓ Sufficient detail
  "question": "Single, answerable question?", // ✓ Yes/no or clear options
  "answers": [
    {"id": "0x1", "title": "Option A", "description": "What happens if chosen"},
    {"id": "0x2", "title": "Option B", "description": "What happens if chosen"}
  ],
  "policyURI": "/ipfs/Qm...",                // ✓ Accessible
  "arbitratorChainID": "42161",              // ✓ Correct chain
  "arbitratorAddress": "0x9C1dA9A04925bDfDedf0f6421bC7EEa8305F9002"  // ✓ KlerosCore on Arbitrum One
}
```

### 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

<Tip>
  Study existing Kleros policies from live products. Escrow V2 and Curate V2 policies are good models. You can find them on IPFS via the dispute template's `policyURI` field inspect live disputes on [court.kleros.io](https://court.kleros.io) to see examples.
</Tip>

### 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

* [ ] `DisputeRequest` emitted with correct parameters
* [ ] `Ruling` emitted after executing ruling
* [ ] `Evidence` events use correct `evidenceGroupID`
* [ ] 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 `immutable` for arbitrator address
* [ ] Pack structs efficiently
* [ ] Avoid redundant storage reads
* [ ] Use `calldata` instead of `memory` where 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 `DisputeRequest` events
* [ ] Alert on `Ruling` events
* [ ] Monitor arbitration fee changes
* [ ] Track dispute resolution times
* [ ] Dashboard for active disputes

**Kleros-specific monitoring:**

* [ ] Monitor `AppealDecision` events from KlerosCore appeals change timeline and cost
* [ ] Subscribe to court parameter changes via `CourtModified` events fee changes affect your cost calculations
* [ ] Track your disputes on [court.kleros.io](https://court.kleros.io) filter by your contract's address
* [ ] If cross-chain: monitor Vea bridge claim/challenge status on [veascan.io](https://veascan.io)
* [ ] Set up alerts for the KlerosCore `Paused` event 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)

**Kleros-specific failure scenarios:**

* [ ] **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](https://blog.kleros.io) and [Discord](https://discord.gg/kleros) for announcements.

* [ ] **Subgraph stability:** Pin to a specific subgraph deployment version in production. Check the [kleros-v2 subgraph README](https://github.com/kleros/kleros-v2/tree/dev/subgraph) for the latest stable deployment IDs.

* [ ] **SDK status:** `@kleros/kleros-sdk` is 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.

<Note>
  Contact the Kleros team via [Discord](https://discord.gg/kleros) or `integrations@kleros.io` before your first production deployment. The team can review your dispute template and advise on court selection.
</Note>

***

## 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](https://github.com/kleros/kleros-v2/tree/dev/contracts/deployments/arbitrum) |
| DisputeKitClassic       | Verify from deployments                                                                                |
| DisputeTemplateRegistry | Verify from deployments                                                                                |
| HomeGateway             | Verify from deployments                                                                                |

```solidity theme={null}
// Querying court parameters on-chain
IKlerosCore core = IKlerosCore(0x33d0b8879368acD8ca868e656Ade97bBcfeB12BA);

// Get arbitration cost for General Court (ID 1) with 3 jurors
bytes memory extraData = abi.encodePacked(uint96(1), uint256(3));
uint256 cost = core.arbitrationCost(extraData);

// Get court parameters
(
    uint96 parent,
    bool hiddenVotes,
    uint256 minStake,
    uint256 alpha,
    uint256 feeForJuror,
    uint256 jurorsForCourtJump,
    uint256[4] memory timesPerPeriod,
    ,
    ,
) = core.courts(1); // courtID = 1
```

<Warning>
  Always verify addresses from the [official repository](https://github.com/kleros/kleros-v2/tree/dev/contracts/deployments) before mainnet deployment. During beta, addresses may be updated through proxy upgrades.
</Warning>

### Useful Links

* [Kleros Court UI](https://court.kleros.io) Monitor disputes
* [GitHub Deployments](https://github.com/kleros/kleros-v2) Contract addresses
* [Kleros Discord](https://discord.gg/kleros) Developer support

***

## Common Last-Minute Issues

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="Hardcoded fees">
    Never hardcode arbitration fees. Always fetch dynamically. Fees change through governance and vary per court.
  </Accordion>

  <Accordion title="Missing refund logic">
    If user overpays arbitration fee, refund the excess.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>
