Core SDK for Mandates, create, canonicalize (JCS), hash, sign (EIP-191), and verify immutable mandate documents with CAIP-10 identities.
npm install @quillai-network/mandates-core
!License

TypeScript SDK for creating, signing, and verifying Mandates: deterministic agreements between a client agent and a server agent. Built to interoperate with the ERC-8004 agent ecosystem.
A Mandate is a signed object that captures:
- who the client and server are
- what the intent is
- what the task body is (core)
- the deadline and metadata required to verify the agreement
This package focuses on the core lifecycle:
- construct a mandate
- sign as server and/or client (EIP-191 and EIP-712)
- verify signatures deterministically
- attach any core payload shape (custom or registry-based)
If you want to build core from a remote primitives registry, use buildCore.
``bash``
npm install @quillai-network/mandates-core
`bash`
yarn add @quillai-network/mandates-core
`ts
import { Mandate, caip10 } from "@quillai-network/mandates-core";
import { Wallet } from "ethers";
const client = Wallet.createRandom();
const server = Wallet.createRandom();
const mandate = new Mandate({
mandateId: "01J9X9A3T3DMD3M3CYAJW1Y0SZ",
version: "0.1.0",
client: caip10(1, client.address),
server: caip10(1, server.address),
createdAt: new Date().toISOString(),
deadline: new Date(Date.now() + 10 60 1000).toISOString(),
intent: "Swap 100 USDC for WBTC",
core: {
kind: "swap@1",
payload: {
amountIn: "100000000",
tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
tokenOut: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
minOut: "165000",
recipient: client.address,
deadline: "2025-12-31T00:00:00Z",
chainId: 1
}
},
signatures: {}
});
await mandate.signAsServer(server, "eip191"); // offer
await mandate.signAsClient(client, "eip191"); // accept
const res = mandate.verifyAll();
console.log(res.server.ok, res.client.ok); // true true
`
core is intentionally flexible. You can attach any structured payload as long as it follows:
`ts`
{ kind: string; payload: Record
`ts`
const custom = new Mandate({
mandateId: "01J9X9A3T3DMD3M3CYAJW1Y0SZ",
version: "0.1.0",
client: caip10(1, client.address),
server: caip10(1, server.address),
createdAt: new Date().toISOString(),
deadline: new Date(Date.now() + 10 60 1000).toISOString(),
intent: "Run my custom task",
core: {
kind: "myTask@1",
payload: { foo: "bar", amount: 123 }
},
signatures: {}
});
`ts
import { buildCore } from "@quillai-network/mandates-core";
const BASE_URL =
"https://raw.githubusercontent.com/quillai-network/mandate-specs/main/spec";
const core = await buildCore(
"swap@1",
{
chainId: 1,
tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
tokenOut: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
amountIn: "100000000",
minOut: "165000",
recipient: client.address,
deadline: "2025-12-31T00:00:00Z"
},
BASE_URL
);
`
* class Mandate
* signAsServer(signer, alg)signAsClient(signer, alg)
* verifyAll()
* verifyRole("client" | "server")
* toJSON()
* buildCore(kind, payload, baseUrl?)
* caip10(chainId, address)
* (helper for eip155:)
* verifyAll() returns a structured object (per-role verification details), not a boolean.buildCore()
* Registry fetching inside may be cached between calls. If you unit test buildCore`, avoid asserting on the exact number of fetch calls unless you reset modules/mocks.
MIT © 2025 QuillAI Network