WRIT Protocol on X@writnetwork on Twitterx.com/writnetworkwrit.networkWRIT Protocol official X account: @writnetworkFollow WRIT Protocol on X: https://x.com/writnetworkTwitter: @writnetwork · Website: writ.network
docs·WRIT Protocol
docs / sdk

TypeScript SDK

A thin client library for proof generation, delegation management, reputation queries, and account derivation. The SDK is optional — every instruction is reachable via Anchor's generated IDL — but it handles WASM loading, circuit artifacts, and PDA math for you.

Package
@writnetwork/sdk
Runtime
Node 20+, modern browsers (WebAssembly, BigInt, SubtleCrypto)
Peer
@solana/web3.js ^1.90
Size
~120 kB gzipped core, +480 kB WASM loaded on demand

Install

$ npm install @writnetwork/sdk @solana/web3.js

Quick surface

app/writ.tstypescript
import {
    Writ,
    generateProof,
    deriveWritAccounts,
    deriveScope,
    ACTION,
} from "@writnetwork/sdk";

const writ = new Writ({
    cluster: "devnet",
    connection,
});

Core APIs

generateProof

Generate a Groth16 proof in the browser (or Node). Returns serialized proof bytes plus the public inputs. The secret trapdoor is derived from a user passphrase via Argon2id.

const { proof, publicInputs } = await generateProof({
    secret: "correct horse battery staple",  // any string
    epoch:  await writ.currentEpoch(),
});

const sig = await writ.register({ proof, publicInputs, authority });
WarningThe passphrase is the sole custody material. Losing it means losing the writ — there is no password reset. For production UX, wrap it in a hardware-backed key or a social recovery scheme; never hand-roll passphrase flows.

createDelegation

await writ.createDelegation({
    slot: 0,
    agent: agentKey,
    programs: [METEORA_ID, RAYDIUM_ID],
    budgetSol: 25,
    durationDays: 14,
    actions: ACTION.SWAP | ACTION.PROVIDE_LIQUIDITY,
});

verify

Client-side verify that mirrors the on-chain CPI. Useful for UI — previewing whether a proposed action will pass before submitting a transaction.

const status = await writ.verify(agentKey);
if (!status.isValid) showRegistrationPrompt();
if (status.score < 500) warnLowReputation(status);

deriveScope / deriveWritAccounts

Helpers to produce the nine account pubkeys needed for a writ_gate::verify CPI.

const accounts = await deriveWritAccounts(connection, agentKey);
// {
//   writAccount, scope_0..scope_4, reputationAccount,
//   sbtTokenAccount, writGateProgram
// }

Full API

MethodPurpose
writ.registerSubmit proof + mint SBT
writ.rotateAuthorityTransfer writ to a new wallet
writ.createDelegationAdd a scope to a slot
writ.revokeDelegationMark a scope as revoked
writ.listDelegationsEnumerate active + expired scopes
writ.verifySimulate writ_gate::verify locally
writ.reputationFetch ReputationAccount
writ.submitReportWrap reputation::submit_report (program-signed)
writ.openDisputeStake SOL to challenge a report
writ.onStatusChangeWebSocket subscription to AgentStatus

React hook

app/hooks/useAgent.tstypescript
import { useAgentStatus } from "@writnetwork/sdk/react";

export function TradePanel({ agent }: { agent: PublicKey }) {
    const { status, loading, error } = useAgentStatus(agent);

    if (loading) return <Spinner />;
    if (!status?.isValid) return <RegisterCTA />;

    return (
        <>
            <ReputationBadge score={status.score} />
            <BudgetMeter remaining={status.scope.budgetRemaining} />
            <SwapForm />
        </>
    );
}

Error handling

SDK methods throw typed errors extending WritError. Use instanceof checks to branch, or the narrowing helpers isWritError.

try {
    await writ.register({ /* ... */ });
} catch (e) {
    if (e instanceof NullifierCollision) {
        toast("Wallet already linked to another writ.");
    } else if (e instanceof ProofInvalid) {
        toast("Proof generation failed — retry or check passphrase.");
    } else {
        throw e;
    }
}

Stability

The SDK is versioned in lockstep with the programs. The major version tracks the on-chain ABI; minor versions add helpers without breaking existing call sites. The 0.x line is devnet-only and may break on any release.