Skip to main content

API Reference

Complete API reference for the Privacy Boost React Native SDK (version 0.2.14). Everything below is derived from the generated UniFFI bindings — signatures match what consumers actually see.

Module exports

Top-level functions:
See Stateless shield helpers for buildShieldPayload and finalizeShield.

PrivacyBoost

Main SDK class. One instance per app; hold it in a module-level ref or a context provider.

Constructor

Configs are created via the factory:
Throws: SdkError.ConfigError if initialization fails, including unsupported persistence storage, OsKeychain without a registered KeychainDelegate, or passkey unlock configuration.

State

Authentication

Connect a wallet, derive privacy keys, authenticate with the backend. Returns an AuthResult tagged union — see AuthResult for all variants and handling.
Complete an authentication flow that returned CredentialRequired.
Complete an authentication flow that returned MnemonicGenerated (first-time user). Call this after the user confirms they’ve saved the recovery phrase.
lock() zeroizes all resident key material and drops the session JWT while keeping the persisted encrypted vault, so the user unlocks again without re-deriving keys. The next key access throws SdkError.NotAuthenticated; call authenticate again to reopen the vault. The idleTtlSecs and absoluteTtlSecs config fields invoke the same lock automatically (see PrivacyBoostConfig). Chain-context handles share the wiped keys but keep their own JWT, so call clearSession() on each of them.

Operations

sendBatch pays several recipients from one set of input notes, in one request: TransferRecipient is { recipient: string; amount: string }, and output order follows the array. The transfer’s output count is the recipient count plus a change note, and the server only proves specific (inputs, outputs) combinations, so past two recipients at most four input notes can be spent; requests no enabled circuit can serve fail with UNSUPPORTED_TRANSFER_SHAPE before submission. unwrapWeth unwraps WETH the user already holds in their wallet back to native ETH — it does not interact with the shielded pool. prepareShield builds a deposit payload without submitting it — for callers that relay the transaction themselves (a gasless relayer, an EIP-7702 session key, or a plain raw transaction). It returns the calldata to relay plus the note commitment; nothing is sent on-chain. Pass undefined for recipient to shield to yourself, or a privacy address to shield to someone else. After relaying, pass the mined receipt to the top-level finalizeShield to recover the on-chain request id.

Earn and gateway

Gateway earn operations deposit into or redeem from a yield vault from inside the pool. The catalog and history reads are public and work before login; earnDeposit and earnRedeem need an authenticated session and a ChainReaderDelegate registered with setChainReader. For a deposit, amount is the net amount that enters the vault and the unshield fee is charged on top; for a redeem it is the share amount. metric is EarnHistoryMetric.TvlUsd or NetApy; period is EarnHistoryPeriod.OneWeek, OneMonth, ThreeMonths, or All. The *Json accessors take the wire names instead, keeping the signatures they shipped with. APY values are fractions (0.05 is 5%), an undefined point value is an upstream gap, and metadata.state reports freshness.
The listEarnVaultsJson, getGatewayConfigJson, getEarnVaultHistoryJson, and getEarnVaultChartsJson methods return the same data as canonical JSON strings for callers that parse the wire shape themselves.

Status polling

Balances & tokens

History & notes

Merkle tree

Audit APIs

For auditable operations — returns all-party visible data, not just the calling user’s. Intended for compliance dashboards and regulators, not for end-user UIs.

App metadata

Private treasury

Per-wallet contacts and transaction labels, stored encrypted on the server and readable only with the session’s keys. Every method requires an authenticated session. A row whose decryptionFailed is true is one the server could no longer open: show it as unreadable, not as missing.
listContacts and listLabels page with an opaque cursor: both arguments default, so listContacts() is the first page at the server’s page size, and the previous page’s nextCursor gets the next one. bulkCreateContacts reports a contact whose privacy address already exists under skipped, with the existing row’s id, rather than failing the batch; clientId on each input is echoed back so you can correlate rows. updateContact takes a patch for every field, so “leave alone” is always Keep and never an undefined that could be read as a clear; nickname and emoji are the two the API can only replace, and Clear on either rejects with SdkError.InvalidInput naming the field. upsertLabel replaces the whole label, so an absent field means “no value”.

Campaigns

Lifetime Startale mission progress for the authenticated user and app. The deposit mission is priced at query time, so it is not monotonic: record the first true your app sees and never downgrade it. campaignTokenId is undefined only when no campaign token is configured, in which case every shielded token counted toward the deposit total.

Session persistence

Identity lookup

Pending transactions

Local bookkeeping for optimistic UI — not persisted across SDK instances.

Chain context

Create a handle scoped to a different chain while sharing the same SDK identity. The handle has its own session and JWT: authenticate it separately with ctx.authenticate(wallet), and clear it separately with ctx.clearSession(), since sdk.lock() wipes the shared keys but leaves the handle’s JWT in place. Every call returns a new handle, so create each one once and keep it. Throws if serverUrl is empty or not an HTTPS URL.
See ChainContextHandle below.

Utilities


ChainContextHandle

Returned by sdk.createChainContext(). Mirrors the main SDK’s chain-scoped operations against a different chain. It shares the parent’s identity keys, so ctx.authenticate(wallet) obtains that chain’s JWT without deriving keys a second time.
The claimable-transfer methods (giftFund, giftFundToWallet, giftFundSecretBearer, giftClaim, giftClaimByCGift, giftClaimFromLink, giftRefund, giftRefundByRecord, getPendingGifts, getGiftRecords, decodeGiftLink) are also on the handle with the same signatures as on sdk (see Gift Methods), along with consolidateNotes, refreshPendingTransactionsDetailed, waitForPreconfirmation, waitForFinality, and importGiftRecords(records: GiftRecord[]), which rehydrates the handle’s sender ledger from persisted records. Portal deposits, earn and swap, audit, and the private treasury stay on the parent sdk, as do resolveIdentity, the amount utilities, setChainReader, and session export. The parent’s pending transactions and token registry reflect its own chain only, so read each chain’s through its handle.

Stateless shield helpers

Top-level named exports for building a deposit payload without a signed-in session — for a backend that holds only a recipient’s privacy address. No wallet, no private keys.
buildShieldPayload builds a recipient-targeted deposit payload from public material only. Resolve tokenId, shieldContractAddress, and teePublicKey from the token catalog / config. An ephemeral sender keypair is generated and discarded internally, and the note is spendable only by recipient. wethContractAddress is required only when shielding native ETH; minShieldAmount (per-token minimum in wei) rejects below-minimum deposits; emitApprove emits the ERC-20 approve call (pass true by default). finalizeShield recovers the on-chain shield request id from the mined receipt of a relayed deposit. Stateless — the caller obtained the receipt from its own relay/RPC. Throws if the deposit reverted or the DepositRequested log is absent. The TransactionReceipt is the same shape returned by WalletDelegate.waitForTransactionReceipt (see WalletDelegate).

Delegate interfaces

WalletDelegate

TokenProvider

KeychainDelegate

Implemented by the app and registered process-wide with registerKeychainDelegate to serve StorageBackend.OsKeychain persistence. Values are opaque bytes; requireBiometry is true when the config selects UnlockMethod.Biometric, and the item must then be stored behind the OS biometric prompt. The optional service argument on registration namespaces the items, which an app running two SDK instances should set.
See Session Storage for a react-native-keychain implementation.

Types

PrivacyBoostConfig

PrivacyBoostConfig.create() defaults approvalOnly to false and both TTL fields to undefined. The SDK discovers the chain-specific AuthRegistry from the configured server; it is not a caller-supplied field. idleTtlSecs and absoluteTtlSecs drive auto-lock, in seconds: the first is how long the resident keys may go unused, the second how long after an unlock they may stay resident at all. undefined or 0n disables the respective timer. Both are checked lazily, on the next key access: once one has elapsed, that access zeroizes the keys and throws SdkError.NotAuthenticated, exactly as sdk.lock() would, and the persisted vault is kept so authenticate can reopen it. They bound key use rather than key residency; call sdk.lock() from your own timer when the keys must be gone at a fixed time. See Auto-lock. persistenceStorage: StorageBackend.OsKeychain stores the encrypted vault through a KeychainDelegate the app implements in JavaScript and registers with registerKeychainDelegate before constructing the SDK; construction throws SdkError.ConfigError otherwise. LocalStorage and IndexedDb are browser backends and are rejected on React Native. See Session Storage.

ChainContextConfig

Everything after chainId is defaulted, so ChainContextConfig.create({ serverUrl, chainId }) is a complete config: the addresses are discovered from that chain’s server and timeoutMs falls back to the SDK-wide 30s. A contract address you do pass has to parse — a malformed one is rejected rather than dropped, so a typo can never fall back to the server-advertised pool.

KeySource

Tagged union — each variant is constructable.

StorageBackend

These enum values are shared with other SDK targets. React Native accepts OsKeychain once a KeychainDelegate is registered and rejects the two browser backends at construction.

UnlockMethod

Passkey is rejected on React Native because iOS and Android do not expose the WebAuthn PRF extension needed for reproducible vault unlock keys. Biometric stores the keychain item with requireBiometry: true, so the delegate places it behind the OS biometric prompt; Pin and Password produce a CredentialRequired result that submitCredential completes.

AuthResult

Tagged union returned by authenticate(). You must handle all five variants.
AccountCreationRequired contains the account ID, canonical account salt, and a prepared EOA transaction (chainId, to, value, data). The SDK validates the target against the AuthRegistry advertised by this deployment’s /api/v1/info. See Getting Started → Connecting a Wallet for worked handling of each variant.

LoginResult

ShieldResult

finalizeShield also returns a ShieldResult.

Call / PreparedShield

Returned by prepareShield and buildShieldPayload. Each Call is a single on-chain call to relay; value and data are 0x-hex.

UnshieldResult / TransferResult

ShieldStatus / TransactionStatus

TokenBalance

RegisteredToken

FeeRates

Schema-v1 responses omit the optional fields and default to a flat transfer fee and BPS unshield fee. Schema v2 selects each mode independently. BPS fees use floor(base * bps / 10000): unshield uses the public exit amount, while a transfer uses only externally sent volume. Pure self-transfers therefore have zero transfer BPS fee. For Gateway operations, pass the executor address and the first four bytes of external calldata to getGatewayFees. The generated React Native binding requires the selector position; pass undefined to request the Gateway-wide default. An exact selector override wins, otherwise the default rate is returned and bound to the requested selector.

Transaction / TransactionNote / TransactionsResult

TransactionHistoryQuery

Every field is defaulted, so TransactionHistoryQuery.create({ tokenId: 1 }) is a valid query and a plain object literal is not needed. undefined fields are unfiltered.

UnspentNote

MerkleTreeStats

Audit result types

See the generated bindings for full field lists; they’re stable but verbose.

PendingTransaction

ExportedSession

data is an opaque serialized core session. Store and pass it back unchanged; do not parse or persist individual key fields.

IdentityResult

AppInfoEntry

Private treasury types

The generated record types spell optional fields as T | undefined rather than ?:, so a plain object literal must list every field. Build them with the generated create({...}) factories instead, as in the Private treasury example: a factory fills in every field the UDL gives a default, which is all of them here except privacyAddress and nickname.

Earn and gateway types

StartaleCampaignProgress


SdkError

Tagged union. Every variant is a constructable class, checked via .instanceOf(err). See the Error Handling guide for patterns and the full variant table.
The string tag is also available at runtime via SdkError_Tags:

Gift Methods

Claimable transfers (gifts) — instance methods on sdk, taking positional arguments. See the Claimable Transfers guide and the concept page.
These methods may not be present in the checked-in generated bindings.
Each fund/claim/refund method returns a TransferResult whose giftRecord and claimLink fields are populated for gift operations.
Fund a gift bound to an Ethereum wallet address that may not be registered with Privacy Boost. amount is wei; refundAfterBlock/currentBlock are block numbers. Returns a TransferResult with claimLink and giftRecord populated.
Fund a gift when the recipient is already a Privacy Boost user, sealing the ciphertext to their viewing key. The third argument is the 194-char privacy address.
Claim a pending gift by its position in getPendingGifts(). acknowledgeUnknownSender must be true — it acknowledges accepting funds from an unknown sender.
Claim a pending gift by its stable commitment cGift (preferred when the list may shift as gifts settle).
Claim a gift directly from a pbgift:v1:... claim link, without a server lookup first.
Refund an unclaimed gift after its deadline, using a local gift record. index is the positional index into getGiftRecords().
Refund an unclaimed gift by supplying every field manually — the fallback when the local gift record is unavailable.
List the pending gifts addressed to the authenticated wallet.
Return the local records the SDK persisted for gifts you funded. These make a gift refundable and travel inside an exported session. Synchronous.
Decode a claim link into a preview offline, with no network call. Synchronous.
A third funding mode, giftFundSecretBearer, binds a gift to a secret instead of a wallet. It is a bearer instrument (whoever holds the link can claim), selected only by that explicit method. See the concept page before considering it.

GiftRecord

PendingGift

GiftLinkPreview

The gift fields (giftRecord, claimLink) on TransferResult are populated only for gift operations; see UnshieldResult / TransferResult.

Portal

Portal deposit addresses. See the Portal Deposits guide and the concept page.
React Native exposes portal lifecycle methods on PrivacyBoost. Low-level portal functions are limited to custodial escape hatches.
The supported path is sdk.createPortal(...), which derives the portal EOA from the recovered nullifying key and keeps the key inside core.
Derive portal E, gaslessly delegate and register it via the server relays, then publish the discovery entry. Omit index to use the next free derivation index.
One page of the authenticated account’s portals with status and derivation index. limit must be between 1 and 100; pass the page’s nextCursor back as cursor to continue, and treat an absent nextCursor as the final page.
One page of the deposits observed at portal. Same cursor and limit semantics.
Return registry/on-chain status for one portal.
Send requestPortalDeposit from the connected wallet and return the transaction hash.
Send cancelPortalDeposit from the connected wallet and return the transaction hash.
Build a signed EIP-1559 transaction that withdraws raw funds resting at the seed-derived portal E. Broadcast the returned raw transaction yourself.

Low-level escape hatches

These module-level functions are imported from @sunnyside-io/privacy-boost-react-native and are for custodial integrations that manage their own portal EOA key. The seed-derived createPortal flow does not expose a private key.
Generate a fresh portal EOA E and its secret private key.
Encode raw withdraw calldata for a custodial integration that already controls its own portal EOA.
Publish the discovery registry entry (E → blind) — the supported submit path so the indexer can credit deposits to the right account.
Return the portal delegate address advertised by the server’s /info, or undefined if the server does not support portals.

PortalEoa


Deposit Cancellation

sdk.shield(...) moves the depositor’s tokens into the pool and holds them there until the sequencer settles the request into the note tree. Almost always that happens within a couple of blocks. When it doesn’t, because of a commitment mismatch, a malformed ciphertext, or a stalled sequencer, the tokens stay in escrow and the depositor reclaims them by cancelling the request on-chain. The server will tell you a shield failed — getShieldStatus(requestId) returns failed for a commitment mismatch or a malformed ciphertext — but it says nothing about the escrow behind it: whether the pool still holds it, who may reclaim it, and when. A stalled sequencer doesn’t even produce that failed row. So use getShieldStatus to notice something went wrong, and these two methods to find out what you can do about it. They read the pool directly and tell you what it would do before you ask anyone to sign.
getDepositCancellation reads chain state, so it needs a ChainReaderDelegate registered with sdk.setChainReader(...). cancelDeposit works without one — it just skips its preflight. It’s the same optional delegate earn uses, and any RPC-connected wallet can back it.
Find a depositRequestId you never kept. Lists the authenticated wallet’s own shield requests in the given public statuses (pending, processing, preconfirmed, completed, failed), oldest first. An empty list means the server’s default of pending. Pass failed to list the shields whose escrow may still be sitting in the pool, then feed each requestId to getDepositCancellation. Served by the server and scoped to the session, so it needs no ChainReaderDelegate and cannot enumerate anyone else’s deposits. failed is a public status the server folds several internal ones into, so it also covers shields rejected as below-minimum or blocked; a stalled sequencer produces no failed row at all and stays pending. Each row is an UnsettledShield: requestId, status, and the optional txHash, blockNumber, createdAt and error.
The fallback when the app kept the shield’s transaction hash but not its request id. Reads the receipt and returns every DepositRequested id the pool emitted, in log order — more than one when an aggregating relayer settled several callers in the same transaction. Empty means the transaction emitted no DepositRequested from the configured pool, which is the answer for a hash that was never a shield rather than an error. Reads the chain, so it needs the same ChainReaderDelegate as getDepositCancellation.
Read the pool and report whether cancelling would succeed for the connected wallet right now, without sending anything. Costs three eth_calls plus one eth_blockNumber, and rejects if no ChainReaderDelegate is set. depositRequestId is the DepositRequested event’s indexed topic1, a uint256. It’s the same value sdk.shield(...) and finalizeShield return as ShieldResult.requestId. Pass it as a decimal string or a 0x-hex string; the depositRequestId on the result is always normalized to decimal.
Cancel a stuck deposit and refund its full escrow to the depositor. Returns the transaction hash. The call preflights through getDepositCancellation and rejects locally, before anything is signed, when the pool would revert. The rejection message is the status reason, so a stuck deposit explains itself instead of burning gas on an opaque revert. Without a ChainReaderDelegate there’s no preflight: the transaction is submitted anyway and the chain arbitrates.

Who can cancel, and when

Only the address that submitted the deposit can cancel it, and the refund goes to that address. For a relayer-submitted shield that’s the relayer, not the note recipient, so a user whose deposit is genuinely theirs can still get NotDepositor back. The cancel delay is measured in blocks and read from the pool’s cancelDelay(). Read the deployed value instead of hardcoding a delay, using cancelDelay, cancellableAtBlock, and blocksRemaining from the returned status.

Cancellation states

state mirrors the reverts in the pool’s cancelDeposit, reported permanent-blocker first rather than in the pool’s own check order. The pool checks the depositor before anything else, and that check would mask the two conditions no caller can clear. A gateway-origin deposit stores the gateway contract as its depositor, never the wallet whose funds routed through it, so it reports GatewayOrigin for every caller and at every point in the delay window. Waiting never makes it cancellable.

DepositCancellation