> For the complete documentation index, see [llms.txt](https://kaisign.gitbook.io/kaisign/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kaisign.gitbook.io/kaisign/developers/deployments.md).

# Smart Contracts

Contract deployment addresses and technical documentation for the Kai-Sign v1-core system.

## Sepolia contract addresses

| Contract                        | Address                                      |
| ------------------------------- | -------------------------------------------- |
| KaiSign Registry                | `0x655084b6A0f2Ee600bd31A71820b5E068b7870d0` |
| PermissionedBToken (bond token) | `0xFfA914D4d69919BBc8c3500e2D5bAAaCeDC21802` |
| Reality.eth ERC20               | `0x3dC3D643912C8f58437F3a381a4223b86C1A347E` |
| Mainnet                         | Coming soon                                  |

The registry is deployed on Sepolia, but the `chainId` argument passed to the registry refers to the chain where the **target contract** lives, not Sepolia.

> **Note**: The contract source code will be open sourced after security audits are complete.

***

## Commit–reveal flow

The KaiSign Registry uses a commit–reveal pattern to prevent front-running of metadata submissions and to bind each submission to a published metadata blob and a bond.

For the end-to-end user workflow, see [Submit Clear Sign Metadata](/kaisign/using-kai-sign/publish-your-docs.md). This page documents the contract surface those steps call into.

### Phase 1 — Commit

The user computes a commitment over the blob hash and a private nonce:

```solidity
bytes32 commitment = keccak256(abi.encode(blobHash, nonce));
```

Then calls:

```solidity
commitSpec(commitment, chainId, extcodehash)
```

| Argument      | Meaning                                                                     |
| ------------- | --------------------------------------------------------------------------- |
| `commitment`  | `keccak256(abi.encode(blobHash, nonce))`                                    |
| `chainId`     | Chain ID of the target contract (not the chain the registry is deployed on) |
| `extcodehash` | Runtime bytecode hash of the target contract                                |

The registry emits `LogCommitSpec` with a `commitmentId` the user must save for the reveal step.

> **Anti-frontrunning**: The private nonce prevents observers from re-using the commitment, and `abi.encode` (not `abi.encodePacked`) is used so the two 32-byte values cannot collide with any other encoding.

### Phase 2 — Approve the bond token

Before revealing, the user must approve the registry to spend `PermissionedBToken`:

```solidity
uint256 minBond = registry.minBond();
PermissionedBToken.approve(registryAddress, tokenAmount); // tokenAmount >= minBond
```

`tokenAmount` is passed into `revealSpec` and must be at least `minBond()` at the time of reveal.

### Phase 3 — Reveal

The same wallet that called `commitSpec` calls:

```solidity
revealSpec(commitmentId, blobHash, nonce, metadataHash, tokenAmount)
```

| Argument       | Meaning                                     |
| -------------- | ------------------------------------------- |
| `commitmentId` | The ID returned from the commit step        |
| `blobHash`     | Nonzero hash of the published metadata blob |
| `nonce`        | The private nonce used in the commitment    |
| `metadataHash` | Nonzero hash of the exact metadata bytes    |
| `tokenAmount`  | Bond amount, ≥ `minBond()`                  |

Reveal requirements enforced on-chain:

* The caller must equal the original committer.
* `blobHash != 0`.
* `metadataHash != 0`.
* `tokenAmount >= minBond()`.
* The registry's bond configuration must not have changed since the commit.

On a successful reveal:

* The registry mints a unique spec `uid` and emits `LogRevealSpec`.
* The registry itself creates the Reality.eth question and emits `QuestionCreated` with a `questionId`. The user does **not** post the Reality.eth question manually.

### Phase 4 — Reality.eth resolution

The default Reality.eth timeout is **48 hours** of no further challenges. Each challenge must at least double the previous bond.

### Phase 5 — Finalize

After Reality.eth finalizes, anyone can call:

```solidity
finalize(uid)
```

* If Reality.eth resolved the question as approved, the spec is inserted into the registry's Merkle tree and becomes discoverable.
* If Reality.eth resolved as rejected, the spec is **not** indexed.

Calling `finalize(uid)` before the Reality.eth question is finalized reverts with `ChallengePeriodActive`. Calling it twice reverts with `AlreadyFinalized`.

***

## Key registry functions

### Submission

| Function                                                               | Description                                                                                                                                                      |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `commitSpec(commitment, chainId, extcodehash)`                         | Phase 1 of submission. Emits `LogCommitSpec` with a `commitmentId`.                                                                                              |
| `revealSpec(commitmentId, blobHash, nonce, metadataHash, tokenAmount)` | Phase 3. Must be called by the original committer with `tokenAmount >= minBond`. Creates the Reality.eth question and emits `LogRevealSpec` + `QuestionCreated`. |
| `finalize(uid)`                                                        | Reads the Reality.eth result and, if approved, indexes the spec.                                                                                                 |

### Query

| Function                                         | Description                                                                               |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| `getLatestSpecForBytecode(chainId, extcodehash)` | Returns `(uid, valid)` for the latest finalized, non-revoked spec for the given bytecode. |
| `getAttestation(uid)`                            | Get full attestation details for a spec.                                                  |
| `computeAttestationLeaf(uid)`                    | Compute the leaf hash for Merkle verification.                                            |
| `verifyAttestationInclusion(uid, merkleProof)`   | Verify a spec is included in the Merkle tree.                                             |
| `minBond()`                                      | The current minimum bond required for `revealSpec`.                                       |

### Example: query by bytecode

```solidity
// Get the bytecode hash of a contract
bytes32 extcodehash;
assembly {
    extcodehash := extcodehash(contractAddress)
}

// Query the registry
(bytes32 uid, bool valid) = registry.getLatestSpecForBytecode(chainId, extcodehash);
if (valid) {
    Attestation memory attestation = registry.getAttestation(uid);
}
```

`valid == false` means no finalized, non-revoked spec exists for that bytecode.

***

## Custom errors

| Error                   | Meaning                                                                                                                    |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `BelowMinBond`          | `tokenAmount` is lower than `minBond`.                                                                                     |
| `BondTokenNotSet`       | Registry bond token configuration is missing.                                                                              |
| `InvalidReveal`         | Wrong sender, wrong nonce, wrong `blobHash`, or a commitment that does not match `keccak256(abi.encode(blobHash, nonce))`. |
| `EmptyBlobHash`         | `blobHash` is zero.                                                                                                        |
| `EmptyMetadataHash`     | `metadataHash` is zero.                                                                                                    |
| `RevealTooEarly`        | Reveal was sent too soon after commit.                                                                                     |
| `ConfigChanged`         | Registry bond configuration changed after the commit.                                                                      |
| `ChallengePeriodActive` | `finalize` called before the Reality.eth question finalized.                                                               |
| `AlreadyFinalized`      | `finalize(uid)` has already been called.                                                                                   |

***

## Bonds

* Bonds are posted in `PermissionedBToken` during `revealSpec`, not in ETH.
* The submitter must approve the registry for at least `minBond()` before calling `revealSpec`.
* Bond outcomes follow Reality.eth: correct answers are rewarded, incorrect answers forfeit the bond.
* Each Reality.eth challenge must at least double the previous bond.

***

## Revocation

Indexed specs carry a `revoked` flag in the Merkle leaf structure. Metadata can be revoked through a new Reality.eth question if it is found to be incorrect, malicious, or outdated. `getLatestSpecForBytecode` skips revoked specs. Hardware wallets should treat revoked metadata as invalid.

***

## Bytecode-based indexing

The registry uses `extcodehash` for contract identification rather than addresses:

| Benefit           | Description                                                                         |
| ----------------- | ----------------------------------------------------------------------------------- |
| **Proxy-safe**    | Works across proxy upgrades (same implementation = same metadata)                   |
| **Cross-chain**   | Same bytecode on different chains can share metadata under different `chainId` keys |
| **Immutable**     | Cannot be changed after contract deployment                                         |
| **Deterministic** | Same source code (and constructor input) always produces the same `extcodehash`     |

### Computing `extcodehash`

```solidity
function getExtcodehash(address target) external view returns (bytes32) {
    bytes32 hash;
    assembly {
        hash := extcodehash(target)
    }
    return hash;
}
```

***

## See also

* [Submit Clear Sign Metadata](/kaisign/using-kai-sign/publish-your-docs.md) — step-by-step submission flow.
* [Leaf Hash Verification](/kaisign/developers/verification.md) — matching off-chain data to on-chain state.
* [API Documentation](/kaisign/developers/overview.md) — querying the registry.
