SDK reference
Everything @offrecord/sdk exports: the client, the account, the helpers, the types, the stages and the error codes.
The client
TypeScript
function createOffrecord(options: OffrecordOptions): OffrecordClientOffrecordClient implements Offrecord.
| Option | Type | Meaning |
|---|---|---|
| apiUrl | string | The Offrecord API. |
| proverUrl | string, optional | The prover that makes a transfer’s proofs. Defaults to <apiUrl>/prover. |
| proverTee | ProverTee, optional | The attestation policy for a prover that is not on the local machine. |
| fetch | typeof fetch, optional | A fetch to use in place of the global one. |
| headers | Record<string, string>, optional | Headers added to every API request. |
| fixture | string, optional | The scenario a fixture server answers with. |
Offrecord
| Method | Returns | What it does |
|---|---|---|
| ring() | Promise<RingInfo> | Reads the Ring’s public state. |
| resolve(address) | Promise<Resolution> | Says whether an address has an account and whether it is on the block list. |
| quote(input) | Promise<Quote> | Prices one send or withdrawal through the relayer, with no account. |
| restore(address) | Promise<Account | null> | Returns the account when its keys were already derived in this browser. No signature. |
| open(wallet) | Promise<Account> | Derives the keys and enrolls them on first use (two message signatures), then returns the account. |
| verifyReceipt(link) | Promise<VerifiedReceipt> | Opens one transfer with the key in the link and matches it to the chain. |
TypeScript
interface Offrecord {
ring(): Promise<RingInfo>
resolve(address: string): Promise<Resolution>
quote(input: QuoteRequest): Promise<Quote>
restore(address: string): Promise<Account | null>
open(wallet: WalletSigner): Promise<Account>
verifyReceipt(link: string): Promise<VerifiedReceipt>
}Account
| Member | Returns | What it does |
|---|---|---|
| address | string | The wallet’s Solana address. |
| sync(onProgress?) | Promise<void> | Scans the Ring’s history with the account’s viewing key. Resolves when caught up. |
| subscribe(listener) | () => void | Calls the listener when a scan finds new notes or a transfer changes status. Returns the function that stops it. |
| balance() | Promise<Holding[]> | What the account holds off the record, per asset. |
| publicBalance() | Promise<Holding[]> | What the wallet holds on the record, per asset. |
| activity() | Promise<Transfer[]> | The account’s deposits, sends, receipts of payment and withdrawals. |
| transfer(id) | Promise<Transfer | null> | One transfer by its id. |
| quote(input, options?) | Promise<Quote> | The relay cost, exit fee and received amount of one send or withdrawal. |
| deposit(input, progress?) | Promise<Transfer> | Moves an asset from the wallet into the Ring. |
| send(input, options?) | Promise<Transfer> | Sends to a Solana address. |
| withdraw(input, options?) | Promise<Transfer> | Sends an asset to a public address. |
| receipt(id) | Promise<string> | A link that opens this one transfer. |
| exportViewingKey() | Promise<string> | The account viewing key as file contents. |
TypeScript
interface Account {
readonly address: string
sync(onProgress?: (state: SyncState) => void): Promise<void>
subscribe(listener: () => void): () => void
balance(): Promise<Holding[]>
publicBalance(): Promise<Holding[]>
activity(): Promise<Transfer[]>
transfer(id: string): Promise<Transfer | null>
quote(input: QuoteRequest, options?: Pick<TransferOptions, 'feePayer'>): Promise<Quote>
deposit(input: MoveInput, progress?: Progress): Promise<Transfer>
send(input: SendInput, options?: TransferOptions): Promise<Transfer>
withdraw(input: SendInput, options?: TransferOptions): Promise<Transfer>
receipt(id: string): Promise<string>
exportViewingKey(): Promise<string>
}Helpers
| Export | What it is |
|---|---|
| AUDITOR_SENTENCE | The sentence the Ring’s auditor key derives from. |
| auditorKeyFromSentence(sentence) | The auditor key for a sentence, as lowercase hex. See The empty seat. |
| formatReceiptLink(signature, key, origin?) | Builds a receipt link. Relative without an origin, absolute with one. |
| parseReceiptLink(link) | Reads the signature and key out of a receipt link. No network request. |
| NATIVE_SOL_MINT | The mint that stands for native SOL. |
| WRAPPED_SOL_MINT | The mint of wrapped SOL, a separate SPL asset. |
| OffrecordError | The error every call rejects with. |
| toOffrecordError(error) | Turns any thrown value into an OffrecordError. |
TypeScript
function auditorKeyFromSentence(sentence: string): Promise<string>
function formatReceiptLink(signature: string, disclosure: ReceiptKey, origin?: string): string
function parseReceiptLink(link: string): ParsedReceiptLink
function toOffrecordError(error: unknown): OffrecordErrorTypes
Amounts are base units as decimal strings. Times are ISO 8601 strings. Addresses and signatures are base58, keys and hashes lowercase hex.
Assets and holdings
TypeScript
type Asset = { mint: string; symbol: string; name: string; decimals: number }
type Holding = { asset: Asset; amount: string }Inputs
TypeScript
type MoveInput = { mint: string; amount: string }
type SendInput = MoveInput & { to: string }
type QuoteRequest = SendInput & { kind: 'send' | 'withdraw' }
type Progress = { onStage?: (stage: Stage) => void }
type TransferOptions = Progress & { feePayer?: WalletSigner }
type WalletSigner = {
address: string
signMessage(message: Uint8Array): Promise<Uint8Array>
signTransaction(transaction: Uint8Array): Promise<Uint8Array>
}Transfers and quotes
TypeScript
type TransferKind = 'deposit' | 'send' | 'receive' | 'withdraw'
type TransferStatus = 'pending' | 'confirmed' | 'failed'
type Transfer = {
id: string
kind: TransferKind
status: TransferStatus
asset: Asset
amount: string
counterparty: string
onTheRecord?: boolean
exitFee?: string
relayCost?: string
time: string
signature: string | null
failure?: string
}
type Quote = {
id: string
route: 'ring' | 'withdrawal'
mint: string
amount: string
to: string
relayCost: string
exitFee: string
receives: string
expiresAt: string
exitFeeBps: number
relayerAddress: string
relayRecipient: string
feeVaultAddress: string
}
type SyncState = { scanned: number; total: number; done: boolean }| Field | Meaning |
|---|---|
| Transfer.counterparty | The other party: the recipient of a send, the sender of a payment received, the destination of a withdrawal, the funding wallet of a deposit. |
| Transfer.onTheRecord | true when a send settled as a withdrawal to an address with no account. |
| Transfer.failure | The reason, when status is failed. |
| Quote.route | ring when the recipient has an account, withdrawal otherwise and for every withdrawal. |
| Quote.amount | The total that leaves the off-record balance. |
| Quote.receives | What the recipient or destination ends up with. |
The Ring
TypeScript
type RingInfo = {
cluster: 'localnet' | 'devnet' | 'mainnet'
programId: string
ringAccount: string
sppProgramId: string
storageProgramId: string
userRegistryProgramId: string
recordsRegistry: string
trackingRegistry: string
auditor: { key: string; sentence: string }
policy: { hash: string; rules: { subject: 'sender' | 'output-owner'; list: 'block' }[] }
blockList: { size: number; root: string; lastSyncAt: string | null; source: string }
notes: number
totals: { asset: Asset; in: string; out: string }[]
exitFeeBps: number
feeVault: { address: string; balances: Holding[] }
relayer: { status: 'live' | 'down'; address: string }
paused: boolean
}
type Resolution = {
address: string
account: boolean
listed: boolean
ringAddress: string | null
}Receipts
TypeScript
type ReceiptKey =
| { kind: 'sender'; key: string }
| { kind: 'recipient'; slot: number; key: string }
type ParsedReceiptLink = { signature: string; disclosure: ReceiptKey }
type OpenedReceiptOutput = {
index: number
asset: Asset
amount: string
recipient: string
commitment: string
}
type VerifiedReceipt = {
signature: string
asset: Asset
amount: string
sender: string
recipient: string
time: string
commitment: string
keyKind: 'sender' | 'recipient'
openedOutputs: OpenedReceiptOutput[]
evidence: { sender: 'stated'; recipient: 'proved' }
}| Field | Meaning |
|---|---|
| VerifiedReceipt.commitment | The commitment published on chain that the rebuilt one matched. |
| VerifiedReceipt.openedOutputs | Every output a sender’s receipt opens, or the one output a recipient’s receipt opens. |
| VerifiedReceipt.evidence | How each party is known: the recipient is proved by the rebuilt commitment, the sender is stated by the transfer’s own metadata. |
Stages
deposit, send and withdraw report each stage to onStage as they reach it.
| Stage | What is happening | Reported by |
|---|---|---|
| signing | The wallet is asked to sign. | deposit, send, withdraw |
| proving | The two proofs are being made. | send, withdraw |
| relaying | The relayer is submitting the transaction. | send, withdraw |
| following | The transaction is submitted and followed to confirmation. | deposit, send, withdraw |
| confirmed | The transaction is confirmed. The call resolves with the transfer. | deposit, send, withdraw |
TypeScript
type Stage = 'signing' | 'proving' | 'relaying' | 'following' | 'confirmed'Error codes
TypeScript
class OffrecordError extends Error {
readonly code: OffrecordErrorCode
readonly details: OffrecordErrorDetails
}| Code | Meaning |
|---|---|
| listed | An address in the call is on the block list. |
| paused | The Ring is paused. |
| insufficient | The balance does not cover the amount plus its costs. |
| rejected | The wallet did not sign. |
| proof | The prover did not return a proof. |
| relay | The relayer refused the transfer or is down. |
| expired | The quote ran out or the transfer did not land in time. |
| network | The API or the RPC did not answer, or the input was not valid. |
| receipt-key | This key does not open this transfer. |
| receipt-unknown | No such transfer. |
| invalid-address | Not a Solana address. |
When a call fails before settlement, nothing has moved.
| Detail | Type | Meaning |
|---|---|---|
| apiCode | string | The API’s own code for the failure. |
| status | number | The HTTP status. |
| retryable | boolean | Whether the same call can be made again. |
| stage | string | The stage the transfer had reached. |
| fieldErrors | Record<string, string[]> | What was wrong with each input field. |
| retryAfterSeconds | number | How long to wait before the next attempt. |
| requestId | string | The id of the request, for tracing it. |
Every field of details is optional.