API Reference
Complete API reference for the Privacy Boost iOS SDK.Generated Documentation
Full API documentation can be generated usingcargo doc:
PrivacyBoost
Main SDK class for iOS.Constructor
config- SDK configuration
SDKError.internalError if initialization fails
Properties
Connection & Authentication Methods
authenticate
wallet- Implementation ofWalletDelegateprotocolkeySource- Optional key derivation source. Ifniland no persistence is configured, defaults to.walletDerived. Ifnilwith persistence configured and no existing vault, an error is thrown.tokenProvider- Optional custom token provider. Ifnil, the SDK sends the login payload directly to the Privacy Boost backend. Supply aTokenProviderto route authentication through your own server.
AuthResult - see AuthResult for all possible outcomes.
Throws:
SDKError.walletErrorif signing failsSDKError.invalidConfigif configuration is invalid or keySource is required but missingSDKError.networkErrorif backend unreachable
submitCredential
authenticate() returns .credentialRequired.
Parameters:
credential- The credential stringtokenProvider- Optional custom token provider for routing authentication through your own server
LoginResult with privacy address and MPK
logout
clearSession
lock
SDKError.notAuthenticated; call authenticate again to reopen the vault. The idle and absolute timers in PrivacyBoostConfig invoke the same lock automatically. Chain-context handles created from this instance share the wiped keys but keep their own JWT, so call clearSession() on each of them separately.
State Accessors
Balance Methods
getBalance
tokenAddress- ERC-20 token contract address
TokenBalance with shielded and wallet amounts
getAllBalances
Fee Methods
getFees
getGatewayFees
gatewaySelector to resolve a selector-specific
override, or nil for the Gateway-wide default.
Vault Operations
deposit
tokenAddress- Token contract addressamount- Amount in wei (as string)
ShieldResult with transaction hash
withdraw
tokenAddress- Token contract addressamount- Amount in wei (as string)recipient- Recipient Ethereum address
UnshieldResult with transaction hash
send
tokenAddress- Token contract addressamount- Amount in wei (as string)recipientPrivacyAddress- Recipient’s 194-char privacy address
TransferResult with transaction hash
sendBatch
tokenAddress- Token contract addressrecipients-TransferRecipient(recipient:amount:)entries in output order, at least one
(inputs, outputs)
combinations, so a longer recipient list limits how many input notes can be
spent — past two recipients, at most four. Requests no enabled circuit can
serve fail with UNSUPPORTED_TRANSFER_SHAPE before submission.
Returns: TransferResult with transaction hash
prepareShield
finalizeShield(...) to recover the on-chain request
id.
Parameters:
tokenAddress- Token contract address (zero address = native ETH)amount- Amount in wei (as string)recipient- (Optional) recipient privacy address. Passnilto shield to yourself.
PreparedShield with the calls to relay and the note commitment
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.
earnDeposit / earnRedeem
amount is the net amount that enters the vault; the unshield fee is charged on top. For a redeem, amount is the share amount. slippageBps of nil uses the gateway default.
listEarnVaults / getEarnVault
availability.deposit.canSubmit on a summary before offering a deposit; retryable says whether a closed window is expected to reopen on its own.
getGatewayConfig
getEarnVaultHistory / getEarnVaultCharts
metric is .tvlUsd or .netApy) or both series fetched together. period is .oneWeek, .oneMonth, .threeMonths, or .all; nil uses the server default. The selectors are enums here and wire strings on the *Json accessors, which keep the signatures they shipped with. APY values are fractions (0.05 is 5%), a nil point value is an upstream gap, and metadata.state reports freshness. A cold cache can briefly fail with a retryable error.
The listEarnVaultsJson, getGatewayConfigJson, getEarnVaultHistoryJson, and getEarnVaultChartsJson methods return the same data as canonical JSON strings for callers that parse the wire shape themselves.
Transaction History
txType- Filter by type: “deposit”, “withdraw”, “transfer”tokenAddress- Filter by tokenlimit- Maximum results
queryTransactionHistory
getTransactionHistory does not take. nil fields are unfiltered.
Parameters:
query- See TransactionHistoryQuery
TransactionsResult with the page of transactions and the cursor for the next page
Session Persistence
exportSession
ExportedSession or nil if not authenticated
importSession
true if session is valid and imported
Private Treasury
Per-wallet contacts and transaction labels, stored encrypted on the server and readable only with the session’s keys. All methods are async, throwSDKError, and require 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
listContacts() is the first page at the server’s page size; pass the previous page’s nextCursor after that.
createContact
privacyAddress and nickname are required and come first; everything after them is defaulted, including clientId, a caller-chosen correlation id that bulk results echo back.
bulkCreateContacts
skipped with the existing row’s id rather than failing the batch.
updateContact
.keep, .clear, or .set(value:)), so “leave alone” is always .keep and never a nil that could be read as a clear. nickname and emoji are the two the API can only replace: .clear on either throws SDKError.InvalidInput naming the field rather than being silently downgraded to .keep.
deleteContact
listLabels
cursor the same way as listContacts.
upsertLabel
deleteLabel
Campaigns
getStartaleCampaignProgress
true your app sees and never downgrade it. campaignTokenId is nil only when no campaign token is configured, in which case every shielded token counted toward the deposit total.
Address Lookup
resolveIdentity
identifier- MPK or Ethereum address
IdentityResult with privacy address and public keys
Chain Context
createChainContext
authenticate(wallet:), and clear it separately with clearSession(); lock() on the parent wipes the shared keys but leaves the handle’s JWT in place. Synchronous; throws if serverUrl is empty or not an HTTPS URL, or if a contract address is present but malformed. Every call returns a new handle, so create each one once and keep it.
Parameters:
config- See ChainContextConfig
Utilities
ChainContextHandle
Returned bycreateChainContext(config:). A chain-scoped facade over one PrivacyBoost identity: it carries the operations whose state is per chain and shares the parent’s keys, so the wallet signs once per chain to obtain that chain’s JWT. Portal deposits, earn and swap, audit, and the private treasury stay on the parent instance, as do resolveIdentity, the amount utilities, setChainReader, and session export.
giftFund, giftFundToWallet, giftFundSecretBearer, giftClaim, giftClaimByCGift, giftClaimFromLink, giftRefund, giftRefundByRecord, getPendingGifts, getGiftRecords, decodeGiftLink) have the same signatures as on PrivacyBoost; see Gift Methods. The handle adds importGiftRecords(records: [GiftRecord]), which rehydrates its sender ledger from persisted records so unclaimed gifts stay refundable through giftRefundByRecord across restarts.
authenticate(wallet:externalToken:) takes only the wallet delegate; the key source and token provider come from the parent. externalToken carries an external identity provider’s token on this chain’s login and defaults to nil.
Module Functions
sdkVersion()— Returns the SDK version stringgenerateMnemonic()— Generates a random 12-word BIP-39 mnemonicregisterKeychainDelegate(delegate:service:): registers the app’s Keychain implementation for.osKeychainpersistence. Process-wide; call it once, before constructing aPrivacyBoostwhose config selects.osKeychain, or construction throws, and a later call replaces the delegate for every instance.servicenamespaces the Keychain items;niluses the SDK’s own name, and an app running two SDK instances or sharing a Keychain group with an extension should pass its own.PrivacyBoost.withPlatformDefaults(config:)in thePrivacyBoostDefaultsproduct registersDefaultKeychainDelegate()for you. See KeychainDelegate Protocol.hasKeychainDelegate(): whether a delegate is registered
Stateless shield helpers
Top-level functions 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.
Types
PrivacyBoostConfig
Both auto-lock timers are checked lazily, on the next key access: once one has elapsed, that access zeroizes the keys and throws
SDKError.notAuthenticated, exactly as lock() would, and the persisted vault is kept so authenticate can reopen it. They bound key use rather than key residency; call lock() from your own timer when the keys must be gone at a fixed time. See Auto-lock. The two fields default to nil, so existing initializer calls keep compiling.
ChainContextConfig
createChainContext. chainId and timeoutMs (request timeout in milliseconds) are required; the optional fields are discovered from that chain’s server when nil. 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
authenticate().
- walletDerived - Derive keys from a deterministic wallet signature (default when no persistence configured)
- mnemonic - Derive keys from a BIP-39 mnemonic phrase
- rawSeed - Derive keys from raw hex entropy (for testing)
AuthResult
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.
LoginResult
TokenBalance
FeeRates
getGatewayFees. gatewayFeeBase is
flat, unshield_amount, or zero and identifies the amount used for fee
calculation.
ShieldResult
Returned byshield and finalizeShield.
UnshieldResult
TransferResult
send(), giftRecord and claimLink are nil; they are
populated by the gift funding methods.
Call
A single on-chain call to relay.value and data are 0x-hex.
PreparedShield
Returned byprepareShield and buildShieldPayload.
TransactionReceipt
The mined-receipt record passed tofinalizeShield.
Transaction
TransactionsResult
One page of history, returned bygetTransactionHistory, getCollapsedTransactionHistory, and queryTransactionHistory.
TransactionHistoryQuery
nil fields are unfiltered. Every field is defaulted, so name only the filters you want: TransactionHistoryQuery(tokenId: 1) is a valid query.
IdentityResult
ExportedSession
data is an opaque serialized core session. Store and pass it back unchanged;
do not parse or persist individual key fields.
Private Treasury Types
Earn and Gateway Types
StartaleCampaignProgress
WalletDelegate Protocol
TokenProvider Protocol
getToken(). Your implementation should forward this payload to your backend, which adds its own credentials and calls the Privacy Boost API.
TokenResponse
Example
KeychainDelegate Protocol
persistenceStorage: .osKeychain. Register an implementation process-wide with registerKeychainDelegate(delegate:) before constructing the SDK, or let PrivacyBoost.withPlatformDefaults(config:) register DefaultKeychainDelegate(). Values are opaque bytes; requireBiometry is true when the config selects .biometric unlock, and the item must then be stored behind the OS biometric prompt. See Session Storage.
SDKError
Gift Methods
Claimable transfers (gifts). See the Claimable Transfers guide and the concept page.These methods may not be present in the checked-in generated Swift bindings.
TransferResult whose giftRecord and
claimLink fields are populated for gift operations.
giftFundToWallet
tokenAddress- Token contract addressamount- Amount in wei (as string)recipientWallet- Recipient’s Ethereum address the gift binds torefundAfterBlock- Block height after which an unclaimed gift may be reclaimedcurrentBlock- Current chain head; pre-validates the refund delay
TransferResult with claimLink and giftRecord populated
giftFund
recipientPrivacyAddress.
Parameters:
recipientPrivacyAddress- Recipient’s 194-char privacy address (the ciphertext’s ECDH target)- Other parameters as in
giftFundToWallet
TransferResult with claimLink and giftRecord populated
giftClaim
getPendingGifts().
Parameters:
index- Position in the pending-gifts listacknowledgeUnknownSender- Must betrue; acknowledges accepting funds from an unknown sender
giftClaimByCGift
cGift (preferred when the list
may shift as gifts settle).
giftClaimFromLink
pbgift:v1:... claim link, without a server lookup
first.
giftRefundByRecord
index
is the positional index into getGiftRecords().
giftRefund
getPendingGifts
getGiftRecords
decodeGiftLink
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
TransferResult are documented under
TransferResult.
Portal
Portal deposit addresses. See the Portal Deposits guide and the concept page.iOS exposes the portal lifecycle as methods on
PrivacyBoost. Low-level portal
functions are limited to custodial escape hatches.createPortal, which derives the portal EOA from the
recovered nullifying key and keeps the key inside core.
createPortal
E, gaslessly delegate and register it via the server relays, then
publish the discovery entry. Pass nil to use the next free derivation index.
listPortalsPage
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.
listPortalDepositsPage
portal. Same cursor and limit semantics.
getPortalStatus
sweepPortal
requestPortalDeposit from the connected wallet and return the transaction
hash.
reclaimPortalDeposit
cancelPortalDeposit from the connected wallet and return the transaction
hash.
withdrawPortal
E. Broadcast the returned raw transaction yourself.
Low-level escape hatches
These top-level functions are for custodial integrations that manage their own portal EOA key. The seed-derivedcreatePortal flow does not expose a private
key.
generatePortalEoa
E and its secret private key.
encodePortalWithdraw
publishPortalRegistry
E → blind) — the supported submit path so
the indexer can credit deposits to the right account.
portalDelegateAddress
/info, or nil
if the server does not support portals.
PortalEoa
Deposit Cancellation
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 setChainReader(reader:). 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.listShieldsByStatus
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 — those stay pending.
Returns: UnsettledShield per row: requestId, status, and the optional
txHash, blockNumber, createdAt and error.
depositRequestIdsFromTransaction
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, so candidate hashes can be swept. Reads the chain, so it needs the same
ChainReaderDelegate as getDepositCancellation.
getDepositCancellation
cancelDeposit would succeed for the connected
wallet right now, without sending anything. Costs three eth_calls plus one
eth_blockNumber, and throws if no ChainReaderDelegate is set.
Parameters:
depositRequestId- TheDepositRequestedevent’s indexedtopic1, auint256. It’s the same valueshield(...)andfinalizeShield(...)return asShieldResult.requestId. Decimal or0x-hex; the result normalizes it to decimal.
DepositCancellation with the escrowed amount, the block the delay
expires at, and a reason you can show the user directly
cancelDeposit
cancelDeposit from the connected wallet and return the transaction hash.
The full escrowed amount goes back to the depositor.
The call preflights through getDepositCancellation and throws locally, before
anything is signed, when the pool would revert. The thrown 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.
Parameters:
depositRequestId- Same idgetDepositCancellationtakes
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
See Also
- Getting Started - Quick start guide
- Wallet Integration - Wallet delegate implementation
- Multi-Chain - Chain contexts
- Session Storage - Persistence and auto-lock