@quillai-network/wachai-validation-sdk
v0.1.0
Published
TypeScript SDK for the Wachai validation protocol (beta): create, sign, and verify ERC-8004 mandates and drive on-chain validation flows on Base Sepolia.
Downloads
99
Readme
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
npm install @quillai-network/wachai-validation-sdk@betaThe 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:
- Register a validator agent (once) → get an
agentId(ERC‑721 NFT). - Create and sign a Mandate between a client and a validator server.
- Send a validation request on‑chain that wraps the Mandate (base64 in a
data:URI). - 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 tohttps://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
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:
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:
const core = await buildCore(
"swap@1",
{ chainId: 1, tokenIn: "...", /* ... */ },
"https://raw.githubusercontent.com/quillai-network/mandate-specs/main/spec"
);Agent registration helpers
Programmatic helper
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 defaulthttps://sepolia.base.org)AGENT_OWNER_PRIVATE_KEYIDENTITY_ADDRESS(else default IdentityRegistry)AGENT_URI(else an inline base64 metadata URI is generated)
Script helper
During setup you can also run:
# Registers an agent and prints AGENT_ID
npx tsx scripts/registerAgent.tsSet at least:
AGENT_OWNER_PRIVATE_KEY
Validation flow (request + status)
1) Request validation
Using the SDK helper:
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
validationRequeston the Validation Registry.
2) Check validation status
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 withresponse === 0pass– validator responded withresponse > 0(score)
CLI scripts (for local testing)
The repo ships with a few useful scripts that exercise the SDK end‑to‑end:
Register agent
npx tsx scripts/registerAgent.tsSend a validation request only
npx tsx scripts/sendValidationRequest.tsCheck validation status only
# pass requestHash as CLI arg npx tsx scripts/checkValidationStatus.ts 0x... # or via env: REQUEST_HASH=0x... npx tsx scripts/checkValidationStatus.tsEnd‑to‑end: create → sign → request → wait → check
npx tsx scripts/requestAndCheckValidation.tsThis 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
getValidationStatusand prints the result.
API overview
Mandates (from mandates-core)
Mandate– construct/sign/verify mandates.buildCore(kind, payload, baseUrl?)– buildcorefrom primitives registry.caip10(chainId, address)– CAIP‑10 identity helper.
Agent registration
registerAgent(options?)– register an ERC‑8004 agent and returnagentId.
Validation
requestValidation(options)– send a validation request for a given mandate and return{ requestHash, txHash, ... }.getValidationStatus(options)– read on‑chain validation status byrequestHash.
High‑level client
WachaiValidationClient– wraps:registerAgent()createMandate()requestValidation()getValidationStatus()
License
MIT
