API Reference
Complete API reference for the Privacy Boost React Native SDK (version0.2.14). Everything below is derived from the generated UniFFI bindings —
signatures match what consumers actually see.
Module exports
buildShieldPayload
and finalizeShield.
PrivacyBoost
Main SDK class. One instance per app; hold it in a module-level ref or a context provider.Constructor
SdkError.ConfigError if initialization fails, including
unsupported persistence storage, OsKeychain without a registered
KeychainDelegate, or passkey unlock configuration.
State
Authentication
AuthResult tagged union — see AuthResult for all
variants and handling.
CredentialRequired.
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
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.
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 whosedecryptionFailed 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
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 withctx.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.
Utilities
ChainContextHandle
Returned bysdk.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.
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 withregisterKeychainDelegate 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.
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
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
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 byauthenticate(). 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 byprepareShield 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
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
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
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
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.
SdkError_Tags:
Gift Methods
Claimable transfers (gifts) — instance methods onsdk, taking positional
arguments. See the
Claimable Transfers guide and the
concept page.
These methods may not be present in the checked-in generated bindings.
TransferResult whose giftRecord and
claimLink fields are populated for gift operations.
amount is wei; refundAfterBlock/currentBlock are block
numbers. Returns a TransferResult with claimLink and giftRecord populated.
getPendingGifts().
acknowledgeUnknownSender must be true — it acknowledges accepting funds from
an unknown sender.
cGift (preferred when the list
may shift as gifts settle).
pbgift:v1:... claim link, without a server lookup
first.
index
is the positional index into getGiftRecords().
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
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.sdk.createPortal(...), which derives the portal EOA from
the recovered nullifying key and keeps the key inside core.
E, gaslessly delegate and register it via the server relays, then
publish the discovery entry. Omit index to use the next free 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.
portal. Same cursor and limit
semantics.
requestPortalDeposit from the connected wallet and return the transaction
hash.
cancelPortalDeposit from the connected wallet and return the transaction
hash.
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.
E and its secret private key.
E → blind) — the supported submit path so
the indexer can credit deposits to the right account.
/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.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.
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.
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.
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 getNotDepositor 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.