SDK Reference — @tracezero/sdk
A typed TypeScript client for the TraceZero relayer/gateway API, plus the authenticated usage telemetry that drives the live counter on the home page.
The client is a thin orchestration layer over the relayer’s HTTP contract
(crates/relayer). It does not reimplement the protocol cryptography (blind
signatures, Poseidon commitments, Groth16 proving, Tor routing) — you produce those
(for example with the in-browser libraries in app/src/lib) and pass them in.
Install
npm install @tracezero/sdk
Client
import { TraceZeroClient } from "@tracezero/sdk";
const client = new TraceZeroClient({
relayerUrl: "http://localhost:8080",
telemetry: { counterUrl: "https://counter.tracezero.dev" }, // optional
});
Methods
| Method | Endpoint | Description |
|---|---|---|
getInfo() | GET /info | RSA public key, fee (bps), and the 7 denomination buckets. |
purchaseCredits(req) | POST /sign | Submit a blinded token + payment proof → blind signature. |
deposit(req, encryptedBody?) | POST /deposit | Submit a commitment. Pass a pre-encrypted body for Tor. |
withdraw(req) | POST /withdraw | Submit a Groth16 proof + public inputs with a timelock. |
executeWithdrawal(nullifierHash) | POST /withdraw/execute | Trigger a pending timelocked withdrawal. |
getMerkleProof(bucket, leaf) | GET /proof/:b/:l | Inclusion proof used to build a withdrawal proof. |
getPool(id) / getAllPools() | GET /pools | Pool / anonymity-set state. |
getPendingWithdrawals() | GET /withdraw/pending | The timelock queue. |
usageStats() | counter GET /stats | Live authenticated usage stats. |
Denomination buckets
import { BUCKET_AMOUNTS, bucketIdForAmount, LAMPORTS_PER_SOL } from "@tracezero/sdk";
// [0.1, 0.5, 1, 5, 10, 50, 100] SOL, in lamports
bucketIdForAmount(1 * LAMPORTS_PER_SOL); // => 2
Authenticated usage telemetry
Every tracked call emits one Ed25519-signed event to the counter Worker. Each SDK install holds a random keypair — an anonymous identity, not a Solana wallet. The event is canonical JSON, signed with that key:
// signed payload (canonical, sorted keys)
{ "nonce": "<16-byte hex>", "op": "deposit", "pub": "<ed25519 pubkey hex>", "ts": 1700000000 }
// envelope POSTed to the counter
{ "payload": "<base64 of the bytes above>", "sig": "<ed25519 sig hex>", "pub": "<pubkey hex>" }
The Worker verifies the signature against the embedded pub and rejects replayed
nonces. So the live counter can only move for real, distinct, authenticated usage —
it cannot be inflated by unsigned or replayed requests, and users stay anonymous.
Opt out
new TraceZeroClient({
relayerUrl: "http://localhost:8080",
telemetry: { enabled: false }, // or simply omit `counterUrl`
});
Read the live aggregate
const stats = await client.usageStats();
// { total, byOp: { deposit, withdraw, ... }, uniqueUsers, updatedAt }
Verifying an event yourself
The same verification the Worker runs is exported, so you can audit the scheme:
import { buildSignedEvent, verifyEnvelope, ed25519 } from "@tracezero/sdk";
const { privateKey, publicKey } = await ed25519.generateKeypair();
const env = await buildSignedEvent("deposit", privateKey, ed25519.toHex(publicKey), 1700000000);
const { ok } = await verifyEnvelope(env); // true; tamper with env.sig or env.payload → false