npm package: @quillai-network/wachai-validation-sdk
Description: TypeScript SDK for the Wachai validation protocol (beta): create, sign, and verify ERC-8004 mandates and drive on-chain validation flows on Base Sepolia.
Latest version: 0.1.0

# wachai-validation-sdk

TypeScript SDK for the **Wachai validation protocol**: create, sign, and verify ERC‑8004 Mandates and drive the full on‑chain validation lifecycle against Wachai’s production verifier on Base Sepolia.

With this SDK you can:

- Register ERC‑8004 validator agents on the **Identity Registry** (Base Sepolia)
- Construct and sign **Mandates** for Wachai validations (client/server)
- Send **on-chain validation requests** to the ERC‑8004 Validation Registry, targeting Wachai’s verifier
- Check **validation status** (pending / fail / pass) for a given request

It is designed as the primary client SDK for integrating with Wachai’s validation layer, not just a thin wrapper around other libraries.

---

## Installation

```bash
npm install @quillai-network/wachai-validation-sdk@beta
```

The package is ESM‑first and targets Node 20+.

---

## Overview & purpose

**Status:** Beta – the API is usable and wired to Wachai’s production verifier on Base Sepolia, but may still evolve. Expect minor breaking changes before v1.0.0.

At a high level, a typical flow looks like:

1. **Register a validator agent** (once) → get an `agentId` (ERC‑721 NFT).
2. **Create and sign a Mandate** between a client and a validator server.
3. **Send a validation request** on‑chain that wraps the Mandate (base64 in a `data:` URI).
4. **Poll or query validation status** to see whether the validator responded and with what score.

Conceptually, Wachai mandates are standard ERC‑8004 Mandates plus Wachai‑specific validation flows (default verifier address, registry defaults, and ergonomic helpers) so you can focus on your application logic.

---

## High-level usage (recommended)

### Configure environment

For Base Sepolia:

- **Required**
  - `AGENT_OWNER_PRIVATE_KEY` – wallet that owns the validator agent NFT and sends txs.
- **Optional**
  - `BASE_SEPOLIA_RPC_URL` – RPC endpoint (defaults to `https://sepolia.base.org`).
  - `IDENTITY_ADDRESS` – custom IdentityRegistry address.
  - `VALIDATION_ADDRESS` / `VALIDATION_REGISTRY_ADDRESS` – custom ValidationRegistry address.
  - `VALIDATOR_ADDRESS` / `VALIDATOR_PRIVATE_KEY` – validator to target (else a default is used).

### End‑to‑end flow with `WachaiValidationClient`

```ts
import { WachaiValidationClient, caip10 } from "@quillai-network/wachai-validation-sdk";

async function main() {
  const client = new WachaiValidationClient(); // uses env / defaults

  // 1) Register a validator agent (once) and remember AGENT_ID
  const agentId = await client.registerAgent();
  console.log("Registered agentId:", agentId.toString());

  // 2) Create a mandate between client and server
  const clientAddress = "0xClientAddress";
  const serverAddress = "0xServerAddress";

  const mandate = client.createMandate({
    client: caip10(84532, clientAddress),
    server: caip10(84532, serverAddress),
    deadline: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
    intent: "Validate my operation",
    core: {
      kind: "myTask@1",
      payload: { foo: "bar" },
    },
  });

  // sign the mandate off‑chain as client and server using mandates-core
  // await mandate.signAsClient(clientWallet, "eip191");
  // await mandate.signAsServer(serverWallet, "eip191");

  // 3) Send a validation request on‑chain
  const { requestHash, txHash } = await client.requestValidation({
    mandate,
    agentId,
  });

  console.log("validationRequest txHash:", txHash);
  console.log("requestHash:", requestHash);

  // 4) Check validation status later (or poll)
  const status = await client.getValidationStatus({ requestHash });
  console.log("status:", status.status, "score:", status.score);
}
```

---

## Working directly with mandates-core

All exports from `@quillai-network/mandates-core` are re‑exported:

```ts
import { Mandate, caip10, buildCore } from "@quillai-network/wachai-validation-sdk";
import { Wallet } from "ethers";

const client = Wallet.createRandom();
const server = Wallet.createRandom();

const mandate = new Mandate({
  client: caip10(1, client.address),
  server: caip10(1, server.address),
  deadline: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
  intent: "Swap 100 USDC for WBTC",
  core: {
    kind: "swap@1",
    payload: { /* ... */ },
  },
  signatures: {},
});

await mandate.signAsServer(server, "eip191");
await mandate.signAsClient(client, "eip191");
const res = mandate.verifyAll();
```

You can also build typed `core` payloads from a primitives registry:

```ts
const core = await buildCore(
  "swap@1",
  { chainId: 1, tokenIn: "...", /* ... */ },
  "https://raw.githubusercontent.com/quillai-network/mandate-specs/main/spec"
);
```

---

## Agent registration helpers

### Programmatic helper

```ts
import { registerAgent } from "@quillai-network/wachai-validation-sdk";

const agentId = await registerAgent({
  // optional; otherwise read from env:
  rpcUrl: process.env.BASE_SEPOLIA_RPC_URL,
  ownerPrivateKey: process.env.AGENT_OWNER_PRIVATE_KEY,
  // identityAddress, agentUri, confirmations are optional overrides
});

console.log("Registered agent id:", agentId.toString());
```

Defaults / env:

- `BASE_SEPOLIA_RPC_URL` (or default `https://sepolia.base.org`)
- `AGENT_OWNER_PRIVATE_KEY`
- `IDENTITY_ADDRESS` (else default IdentityRegistry)
- `AGENT_URI` (else an inline base64 metadata URI is generated)

### Script helper

During setup you can also run:

```bash
# Registers an agent and prints AGENT_ID
npx tsx scripts/registerAgent.ts
```

Set at least:

- `AGENT_OWNER_PRIVATE_KEY`

---

## Validation flow (request + status)

### 1) Request validation

Using the SDK helper:

```ts
import { requestValidation } from "@quillai-network/wachai-validation-sdk";

const { requestHash, txHash } = await requestValidation({
  mandate,             // Mandate or MandateJSON
  agentId: 123n,       // or number/string, or AGENT_ID from env
  // validatorAddress, rpcUrl, ownerPrivateKey, validationRegistryAddress are optional
});
```

This:

- Converts the mandate to JSON and base64 (`mandateBase64`).
- Wraps it in a structured payload + `data:application/json;base64,...` URI.
- Calls `validationRequest` on the Validation Registry.

### 2) Check validation status

```ts
import { getValidationStatus } from "@quillai-network/wachai-validation-sdk";

const status = await getValidationStatus({ requestHash });

console.log(status.status);          // "pending" | "fail" | "pass"
console.log(status.score);           // null, 0, or validation score
console.log(status.responseHash);    // bytes32 of the response
console.log(status.validatorAddress);
console.log(status.agentId?.toString());
```

Status semantics (mirrors the reference server example):

- `pending` – no response yet (`responseHash == 0x0...0`)
- `fail` – validator responded with `response === 0`
- `pass` – validator responded with `response > 0` (score)

---

## CLI scripts (for local testing)

The repo ships with a few useful scripts that exercise the SDK end‑to‑end:

- **Register agent**

  ```bash
  npx tsx scripts/registerAgent.ts
  ```

- **Send a validation request only**

  ```bash
  npx tsx scripts/sendValidationRequest.ts
  ```

- **Check validation status only**

  ```bash
  # pass requestHash as CLI arg
  npx tsx scripts/checkValidationStatus.ts 0x...
  # or via env:
  REQUEST_HASH=0x... npx tsx scripts/checkValidationStatus.ts
  ```

- **End‑to‑end: create → sign → request → wait → check**

  ```bash
  npx tsx scripts/requestAndCheckValidation.ts
  ```

  This script:

  - Creates a mandate (client/server addresses).
  - Signs it as both roles (client + server) using EIP‑191.
  - Sends `validationRequest`.
  - Waits ~20 seconds (configurable via `VALIDATION_WAIT_MS`).
  - Calls `getValidationStatus` and prints the result.

---

## API overview

- **Mandates (from mandates-core)**  
  - `Mandate` – construct/sign/verify mandates.
  - `buildCore(kind, payload, baseUrl?)` – build `core` from primitives registry.
  - `caip10(chainId, address)` – CAIP‑10 identity helper.

- **Agent registration**  
  - `registerAgent(options?)` – register an ERC‑8004 agent and return `agentId`.

- **Validation**  
  - `requestValidation(options)` – send a validation request for a given mandate and return `{ requestHash, txHash, ... }`.
  - `getValidationStatus(options)` – read on‑chain validation status by `requestHash`.

- **High‑level client**  
  - `WachaiValidationClient` – wraps:
    - `registerAgent()`
    - `createMandate()`
    - `requestValidation()`
    - `getValidationStatus()`

---

## License

MIT