Skip to Content
SDK ReferenceTypeScript APInotes
SDK reference (auto)

notes

Interfaces

TokenBalance

A token-grouped balance line as the SDK reports it.

Properties

PropertyTypeDescription
tokenstringToken contract address (lowercased).
symbolstringToken symbol used by the stored notes (best-effort).
rawbigintSum of note.amount across unspent notes for this token.

AvailableBalanceOpts

Properties

PropertyTypeDescription
chainId?numberOptional: filter to a single chain. Notes without a chainId are treated as “any chain” so test/in-memory data still surfaces.
spentIds?ReadonlySet<string>Optional: ids of notes the caller knows are spent. The note adapter does not track nullifiers — apps that have observed on-chain spends should pass them here so the balance does not count notes that are dead in protocol state.

ClaimPackage

Per-recipient claim payload sent from the operator who settled the run to each recipient. Carries the per-claim secret + the inclusion proof needed to claim against PrivateSettlement.

Wire format: JSON-serializable strings (decimal-encoded bigints) so the package can travel through URLs, QR codes, email bodies, etc. without per-consumer BigInt-awareness. Decoding into native bigints happens once at the recipient before proving.

Properties

PropertyTypeDescription
version1-
chainIdnumber-
settlementAddressstringAddress of PrivateSettlement that holds the claims group.
claimsRootstringBytes32 hex of the claims-tree root the settle stamped.
recipientstringRecipient EOA — must equal the wallet submitting the claim; the circuit binds the signed recipient to the proof.
tokenstring-
tokenSymbolstringDisplay symbol (e.g. “USDC”) shown to the recipient. The authoritative on-chain mapping is token; this is purely UX copy so the recipient page can show “1 USDC” instead of “0x2279…”.
tokenDecimalsnumberERC-20 decimals for token. Carried in the package so the recipient page can format the amount without an extra RPC call (and so the package stays self-contained across chains).
amountstringDecimal string preserving bigint precision across JSON.
releaseTimestringUnix-seconds release time, decimal string.
secretstringPer-claim secret, decimal string.
leafIndexnumber0..15 — leaf index within the 16-leaf claims tree.
pathElementsstring[]Decimal-string siblings on the path from the leaf to the root.
pathIndicesnumber[]0/1 bits for pathElements: 1 means the sibling is the left child at that level.
senderLabel?stringOptional display labels — purely informational, not signed.
runLabel?string-
relayerUrl?stringOptional relayer base URL the operator settled through. When present, the recipient page can offer a gasless claim path (POST <relayerUrl>/api/private-claim) — the relayer pays gas in exchange for having settled the run. Absent for runs whose relayer was unreachable / offline at settle time.
ephemeralPubKey?stringEIP-5564 ephemeral public key — set only for stealth recipients. When present, recipient is the one-time stealth address (not the recipient’s normal EOA), and the receiver derives the matching private key locally with their meta-address keys. Sent alongside the package via the same off-chain channel (email / messenger), never on-chain — stealth privacy depends on the ephPub staying off-chain so a leaked viewing key alone doesn’t unmask all incoming claims.

PendingDepositNote

The fields assessDepositRetry reads off a vault note. A StoredNote satisfies this structurally, so callers pass notes straight through.

Properties

PropertyTypeDescription
commitmentbigintPoseidon commitment — looked up against the on-chain tree.
txHash?stringDeposit tx hash, when we broadcast it ourselves (sequential path). Empty/undefined for the atomic-batch path, where only a 5792 bundle id exists and the per-tx hash isn’t known until confirmed.
leafIndexnumber-1 while the deposit hasn’t reconciled to a leaf yet.
status?"failed"Set once the deposit is proven to have reverted.

MinimalReceipt

A tx receipt, reduced to the one field the guard needs.

Properties

PropertyTypeDescription
statusnumber | null1 mined-ok, 0 reverted, null for ethers’ pre-confirmation shape.

RetryGuardDeps

Properties

PropertyTypeDescription
refreshTree() => voidForce one commitment-tree re-hydrate. Fire-and-forget (the SDK’s tree.refresh returns void); the tree mutates its shared index in place, so we poll RetryGuardDeps.findIndex afterwards.
findIndex(commitment) => numberSynchronous lookup against the in-memory tree index. >= 0 means the commitment has landed on-chain. The tree verifies its own hydration (rejecting forked / out-of-sync leaf sets), so a hit is trustworthy positive evidence.
getReceipt?(txHash) => Promise<MinimalReceipt | null>Fetch a tx receipt. null means either still-pending or dropped/unknown — ethers can’t tell them apart from the receipt alone, so RetryGuardDeps.getTransaction disambiguates. Only called for notes that carry a txHash. Optional: when absent (no wallet provider), the guard falls back to tree-only evidence.
getTransaction?(txHash) => Promise<unknown>Fetch the tx itself. null = the node doesn’t know this hash — i.e. it was dropped from the mempool or never broadcast, so a retry must be allowed rather than blocked forever. A non-null result with a null receipt is a genuine mempool-pending tx → block. Optional; without it a null receipt is treated as ambiguous.
signal?AbortSignalAbort the recheck early (e.g. the user hit Cancel). When aborted the guard stops polling and returns block: false; the caller is responsible for noticing the abort and abandoning the deposit rather than proceeding.
sleep?(ms) => Promise<void>Injectable sleep — overridden in tests to avoid real timers.

RetryGuardResult

Properties

PropertyTypeDescription
blockbooleantrue when positive on-chain evidence shows a retry would duplicate a deposit (landed / still-pending) — a hard block.
confirm?booleantrue when the prior deposit can be neither confirmed nor cleared (an atomic-batch note with no tx hash that isn’t in the tree, or a receipt we couldn’t read). Not safe to auto-allow or permanently block — the caller should ask the user to confirm before retrying. Mutually exclusive with block.
message?stringUser-facing reason; set when block or confirm.

IndexedDbAdapterOpts

Properties

PropertyTypeDescription
dbName?stringDatabase name. Apps that want to isolate notes per network / account should encode the discriminator into this name.
storeName?string-
version?number-
encrypt?(plaintext) => Promise<string>Optional encryption-at-rest. When BOTH are provided, each note’s sensitive payload (the preimage — ownerSecret + salt — plus amount and metadata) is encrypted before it is written to IndexedDB and decrypted on load; only the record id (the key path) stays in clear. A same-origin XSS / malicious extension / device-access read of IDB then yields ciphertext instead of spendable-linkable secrets. The app supplies the crypto — e.g. WebCrypto AES-GCM under a key derived from a wallet signature — so the SDK stays crypto-agnostic and the key lives in the app’s control (mirroring the EdDSA-key encryption flow). Must round-trip: await decrypt(await encrypt(s)) deep-equals s. Back-compat / migration: with no encrypt, records are written as plaintext (previous behaviour). Legacy plaintext records already in IDB are read transparently and re-written encrypted on their next put. If decrypt is absent but encrypted records exist, they are skipped (logged once) rather than crashing the load.
decrypt?(ciphertext) => Promise<string>-

NoteCipher

encrypt/decrypt pair consumable by IndexedDbAdapterOpts (and any other storage adapter that takes the same hooks).

Properties

PropertyType
encrypt(plaintext) => Promise<string>
decrypt(ciphertext) => Promise<string>

StoredNote

Persistent note record. Carries everything an app needs to spend (note preimage), display (symbol, amount, label), and reconcile against chain state (leafIndex, txHash, chainId).

BigInts are kept native here; adapters handle wire-format serialization (hex strings) at the storage boundary.

Properties

PropertyTypeDescription
idstringStable per-record id (uuid).
labelstringDisplay label, e.g. lot-1.
symbolstringToken symbol shown in the UI.
amountstringDisplay amount string (already formatted for the UI). Not used for math — note.amount is the canonical raw value.
noteCommitmentNoteFull commitment-note preimage. The secret material that lets the holder spend the deposit.
commitmentbigintPoseidon commitment derived from note. Cached so callers don’t recompute on every render.
leafIndexnumberOn-chain leaf index. -1 when the deposit’s CommitmentInserted event hasn’t been reconciled yet.
status?"failed"Set to "failed" once the deposit transaction is proven to have NOT landed on-chain — i.e. its receipt reverted (status === 0). Such a note’s commitment was never inserted, so it can never reconcile to a leaf and no funds were escrowed for it; the UI filters it out instead of showing it as Pending forever. Only set on a reverted receipt — a merely-not-yet-mined or successfully- mined-but-unindexed deposit is left untouched (deleting those could strand a real, recoverable note).
failedAt?numberWhen status was set (ms epoch).
txHash?stringDeposit transaction hash, when known.
chainId?numberChain id this note belongs to — apps should only show notes for the active network.
account?stringWallet address (lowercased, 0x-prefixed) that deposited this note. Used so the escrow / vault UI only shows notes whose spendable secret the connected wallet plausibly holds — without it, every wallet sharing a workspace folder sees every other wallet’s notes and gets misleadingly Pending / Available chips for funds it can’t actually claim. Optional: notes written before this field existed (and notes the user explicitly wants visible across wallets) leave it undefined and pass through any accountKey filter.
createdAtnumberWhen the note was added (ms epoch).

NoteStorageAdapter

Storage adapter contract. Implementations: in-memory (tests / SSR), IndexedDB (browser), and (future) AsyncStorage / SQLite for RN.

Methods

ready()
ready(): Promise<void>;

Resolve once the adapter is ready (e.g. IDB open completed). Idempotent: subsequent calls return the same promise.

Returns

Promise<void>

loadAll()
loadAll(): Promise<StoredNote[]>;

Load all notes, ordered oldest → newest by createdAt.

Returns

Promise<StoredNote[]>

put()
put(note): Promise<void>;

Insert or update a note by id.

Parameters
ParameterType
noteStoredNote
Returns

Promise<void>

remove()
remove(id): Promise<void>;

Remove by id. Idempotent — a missing id is a no-op.

Parameters
ParameterType
idstring
Returns

Promise<void>

clear()
clear(): Promise<void>;

Remove every note. Used for “reset wallet” / “switch account”.

Returns

Promise<void>

lockedCount()?
optional lockedCount(): number;

Number of records present in the backing store that the last load could NOT recover — e.g. encrypted rows read by an adapter whose decryption key isn’t available yet. Meaningful only after loadAll() resolves; adapters without a locked concept omit it (read as 0). The vault provider surfaces this so apps can raise an “unlock” affordance instead of silently under-reporting.

Returns

number

Variables

DEPOSIT_CONFIRMING_WINDOW_MS

const DEPOSIT_CONFIRMING_WINDOW_MS: number;

Window (ms) after a deposit note is persisted during which we treat it as “still confirming” and block a second deposit. Past this, a note stuck at leafIndex < 0 is almost certainly a dropped tx or a discarded cross-app change note (the vault is shared across products), so it must NOT keep funding locked forever.

Functions

getAvailableBalance()

function getAvailableBalance(adapter, opts?): Promise<TokenBalance[]>;

Compute available balance per token from a notes adapter.

This is a local read. It sums what the wallet sees in storage. Notes that have been spent on-chain but not yet reconciled by the adapter (e.g. used in another tab) will count until spentIds marks them, so callers that need authoritative chain state should pair this with their nullifier-watch loop.

Returns one entry per distinct token, in descending balance order so UIs can render the largest line first without sorting.

Parameters

ParameterType
adapterNoteStorageAdapter
optsAvailableBalanceOpts

Returns

Promise<TokenBalance[]>


encodeClaimPackage()

function encodeClaimPackage(pkg): string;

Base64url-encode a ClaimPackage. The result is URL-fragment safe (no +, /, or = chars) so callers can drop it into the hash segment of a claim link without further escaping.

Parameters

ParameterType
pkgClaimPackage

Returns

string


decodeClaimPackage()

function decodeClaimPackage(encoded): ClaimPackage;

Decode a base64url-encoded ClaimPackage. Throws with a clear message when the payload is malformed, the JSON is invalid, or the version / shape doesn’t match — so a caller doesn’t have to unwrap a chain of unknown checks before showing the user.

Parameters

ParameterType
encodedstring

Returns

ClaimPackage


isClaimPackage()

function isClaimPackage(v): v is ClaimPackage;

Parameters

ParameterType
vunknown

Returns

v is ClaimPackage


isCompressedPubkeyHex()

function isCompressedPubkeyHex(v): v is string;

Shared shape check for an EIP-5564 compressed secp256k1 pubkey (the 0x + 33 hex bytes that goes into ephemeralPubKey and similar fields). Exported so storage modules and ABI callers share one definition.

Parameters

ParameterType
vunknown

Returns

v is string


isLiveNote()

function isLiveNote(n): boolean;

A note that hasn’t been flagged a phantom/failed deposit (its tx reverted → never inserted). Centralizes the “exclude failed” filter shared across balance summaries, the confirming-deposit guard, and the note lists so the rule stays in one place.

Parameters

ParameterType
n{ status?: "failed"; }
n.status?"failed"

Returns

boolean


isPendingDeposit()

function isPendingDeposit(n): boolean;

A deposit that has been broadcast but not yet reconciled to an on-chain leaf — i.e. still “in flight”. Excludes phantom (failed) notes. The single predicate behind the confirming-deposit guard, the on-chain retry recheck, and the wizard’s pending filter, so they can’t drift on what “pending” means.

Parameters

ParameterType
n{ leafIndex: number; status?: "failed"; }
n.leafIndexnumber
n.status?"failed"

Returns

boolean


hasConfirmingDeposit()

function hasConfirmingDeposit( tokenNotes, nowMs, windowMs?): boolean;

True when a recently-created note for the run’s token is still pending on-chain (leafIndex < 0) within the confirming window — i.e. a deposit we just broadcast is most likely mid-confirmation, so a second deposit would duplicate it. Time-bounded on createdAt so a phantom/never-reconciling pending note can’t permanently block deposits (the bug a naive pendingRaw > 0 check would introduce). Callers pass the token-filtered notes + Date.now().

Parameters

ParameterTypeDefault value
tokenNotesreadonly { leafIndex: number; createdAt: number; status?: "failed"; }[]undefined
nowMsnumberundefined
windowMsnumberDEPOSIT_CONFIRMING_WINDOW_MS

Returns

boolean


assessDepositRetry()

function assessDepositRetry(pending, deps): Promise<RetryGuardResult>;

On-chain recheck before allowing a deposit retry. Call this only for pending notes that have already aged past the wall-clock confirming window — the in-window block stays enforced separately and unconditionally (see hasConfirmingDeposit). This closes the gap where a deposit that genuinely landed (but whose confirmation/reconcile lagged past the window) would otherwise let a confused user re-deposit and lock 2× the funds.

Conservative by construction: it only adds a block — it never trusts a bare findIndex < 0 to permit a retry. Verdicts:

  • a commitment in the tree → block (landed)
  • a status === 1 receipt → block (landed)
  • a known tx with a null receipt → block (mempool)
  • a status === 0 receipt → allow (reverted)
  • a dropped tx (unknown to the node) → allow (safe)
  • no txHash / unreadable receipt / unknown status / no reader (can’t classify) → confirm (ambiguous)

Parameters

ParameterType
pendingreadonly PendingDepositNote[]
depsRetryGuardDeps

Returns

Promise<RetryGuardResult>


createFolderNoteAdapter()

function createFolderNoteAdapter(opts?): NoteStorageAdapter;

Build a folder-backed NoteStorageAdapter. Throws on put, remove, or clear when no folder is selected — callers should guard with hasFolder() or wait for useFolderStorage().ready in React contexts. loadAll returns [] instead of throwing so a vault that mounts before the folder is picked still gets an empty list rather than a render-time error.

Identity model: id is content-addressed from commitment (c-<hex>), so a record written by Pay and a record written by frontend with the same commitment have the same id. This makes remove(id) work across apps and keeps any caller-side dedup-by- id consistent regardless of which app produced the file.

Parameters

ParameterType
optsFolderAdapterOpts

Returns

NoteStorageAdapter


idForCommitment()

function idForCommitment(commitment): string;

Content-addressed id for a commitment. Hex of the commitment is unique per note (Poseidon collision resistance) and matches the same record across reads from Pay or frontend. Exported so vault providers stamp the same id at put time, which keeps the in-memory vault and the on-disk record consistent.

Parameters

ParameterType
commitmentbigint

Returns

string


createIndexedDbNoteAdapter()

function createIndexedDbNoteAdapter(opts?): NoteStorageAdapter;

IndexedDB-backed note storage. Uses a single object store keyed by note.id. Survives page reload + browser restart. Falls back to in-memory state on platforms without IDB (private-mode quotas, SSR, broken handles) — failures don’t surface to the caller, but are logged once per session.

Security model (read before relying on this in production)

By default this adapter persists note.ownerSecret, note.salt, and note.amount as plaintext hex in the browser’s IndexedDB. Any JavaScript on the same origin (stored XSS, malicious extensions, dev-tools by anyone with device access) can then read this material. It does not move funds on its own — spending also requires the EdDSA private key bound into the v2 commitment (which apps store encrypted) — but it DOES leak the link between the note and the user’s other on-chain activity, defeating the privacy goal.

Pass encrypt / decrypt in IndexedDbAdapterOpts to opt into encryption-at-rest: the sensitive payload is stored as ciphertext and only the record id remains in clear. The app owns the crypto + key (e.g. WebCrypto AES-GCM under a wallet-signature-derived key), matching the EdDSA-key encryption flow. With encryption enabled, an IDB read yields no preimage/amount. Without it, treat IDB as semi-trusted storage.

Parameters

ParameterType
optsIndexedDbAdapterOpts

Returns

NoteStorageAdapter


createMemoryNoteAdapter()

function createMemoryNoteAdapter(): NoteStorageAdapter;

In-memory note adapter — no persistence. Useful for tests, SSR, and storybook stories. Each instance has its own state; callers should share a single instance per “session” if they want cross-component visibility.

Returns

NoteStorageAdapter


createSignatureNoteCipher()

function createSignatureNoteCipher(signature): NoteCipher;

Derive an AES-GCM-256 note cipher from a wallet ECDSA signature — the same 65-byte personal_sign output deriveEdDSAKey returns, so an app that already derived its trading key can enable note encryption-at-rest without a second wallet prompt.

Key path: HKDF-SHA256(ikm = signature bytes, salt/info = fixed domain-separation labels) → non-extractable AES-GCM-256 CryptoKey. The key lives only in memory (like the signature itself); losing it is fine — it’s re-derivable from the wallet by re-signing.

Each encrypt call uses a fresh random 96-bit IV, so identical plaintexts produce unlinkable ciphertexts. decrypt throws on a tampered envelope (GCM auth failure) — storage adapters treat that as a skip, not a crash.

Parameters

ParameterType
signaturestring

Returns

NoteCipher