API Reference
Complete API reference for the Privacy Boost Android SDK.Generated Documentation
Full API documentation can be generated usingcargo doc:
PrivacyBoost
Main SDK class for Android.Constructor
config- SDK configuration
Properties
Connection & Authentication Methods
authenticate
wallet- Implementation ofWalletDelegateinterfacekeySource- Optional key derivation source. Ifnulland no persistence is configured, defaults toKeySource.WalletDerived. Ifnullwith persistence configured and no existing vault, an error is thrown.tokenProvider- Optional custom token provider. Ifnull, 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 null 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. Passnullto 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. All of these are suspend functions; call them inside withContext(Dispatchers.IO).
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 null 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 EarnHistoryMetric.TVL_USD or NET_APY) or both series fetched together. period is ONE_WEEK, ONE_MONTH, THREE_MONTHS, or ALL; null 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 null 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. null fields are unfiltered. Suspend, so call it inside withContext(Dispatchers.IO).
Parameters:
query- See TransactionHistoryQuery
TransactionsResult with the page of transactions and the cursor for the next page
Session Persistence
exportSession
ExportedSession or null 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 suspend functions (call them insidewithContext(Dispatchers.IO)), throw SDKError, 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
StringPatch.Keep, StringPatch.Clear, or StringPatch.Set(value), and the MetadataPatch equivalents), so “leave alone” is always Keep and never a null 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 null only when no campaign token is configured, in which case every shielded token counted toward the deposit total. Suspend, so call it inside withContext(Dispatchers.IO).
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 SDKError 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. Methods that return a network result are suspend functions; call them inside withContext(Dispatchers.IO).
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: List<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 null.
Module Functions
sdkVersion()— Returns the SDK version stringgenerateMnemonic()— Generates a random 12-word BIP-39 mnemonicregisterKeychainDelegate(delegate, service): registers the app’s Keystore implementation forStorageBackend.OS_KEYCHAINpersistence. Process-wide; call it once, before constructing aPrivacyBoostwhose config selectsOS_KEYCHAIN, or construction throws, and a later call replaces the delegate for every instance.servicenamespaces the stored items;nulluses the SDK’s own name, and an app running two SDK instances should pass its own.PrivacyBoostDefaults.create(context, config)incom.privacyboost.defaultsregistersDefaultKeystoreDelegate(context)for you. See KeychainDelegate Interface.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
approvalOnly to true for approval-only EOA accounts. The SDK discovers
the chain-specific AuthRegistry from the configured server.
persistenceStorage = StorageBackend.OS_KEYCHAIN requires a KeychainDelegate
registered with registerKeychainDelegate (or through
PrivacyBoostDefaults.create) before construction; LOCAL_STORAGE and
INDEXED_DB are browser backends and are rejected. persistenceUnlock may be
NONE, PIN, PASSWORD, or BIOMETRIC; PASSKEY is rejected.
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. null or 0u 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
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. Both fields default to null,
so existing constructor 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 null. 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
Call
A single on-chain call to relay.value and data are 0x-hex.
PreparedShield
Returned byprepareShield and buildShieldPayload.
TransactionReceipt
The mined-receipt type passed tofinalizeShield.
Transaction
TransactionsResult
One page of history, returned bygetTransactionHistory,
getCollapsedTransactionHistory, and queryTransactionHistory.
TransactionHistoryQuery
null fields are unfiltered. Every field is defaulted, so name only the filters you want: TransactionHistoryQuery(tokenId = 1u) 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 Interface
TokenProvider Interface
getToken(). Your implementation should forward this payload to your backend, which adds its own credentials and calls the Privacy Boost API.
TokenResponse
Example
KeychainDelegate Interface
persistenceStorage = StorageBackend.OS_KEYCHAIN. Register an implementation process-wide with registerKeychainDelegate before constructing the SDK, or let PrivacyBoostDefaults.create(context, config) register DefaultKeystoreDelegate(context). Values are opaque bytes; requireBiometry is true when the config selects UnlockMethod.BIOMETRIC, and the item must then be stored under a Keystore key that requires a class-3 biometric. The default delegate expects the app to complete its own BiometricPrompt before the SDK reads or writes such an item. See Session Storage.
SDKError
Gift Methods
Claimable-transfer (gift) methods on thePrivacyBoost instance. See the
Claimable Transfers guide for usage and the
concept page for the trust model. Suspend
methods should be called inside withContext(Dispatchers.IO).
giftFundToWallet
tokenAddress- Token contract addressamount- Amount in wei (as string)recipientWallet- Recipient’s Ethereum address the gift binds to (irrevocable)refundAfterBlock- Block height after which an unclaimed gift may be reclaimedcurrentBlock- Current chain head; pre-validates the refund delay
TransferResult with giftRecord (persist it) and claimLink
giftFund
tokenAddress- Token contract addressamount- Amount in wei (as string)recipientPrivacyAddress- Recipient’s 194-char privacy address (ECDH target)recipientWallet- Recipient’s Ethereum address the gift binds to (irrevocable)refundAfterBlock- Block height after which an unclaimed gift may be reclaimedcurrentBlock- Current chain head; pre-validates the refund delay
TransferResult with giftRecord (persist it) and claimLink
giftClaim
getPendingGifts().
Parameters:
index- Position in the pending-gift listacknowledgeUnknownSender- Must betrue; consents to funds from a hidden sender
giftClaimByCGift
cGift. Preferred over index
when the pending list may shift as gifts settle.
Parameters:
cGift- Stable gift commitmentacknowledgeUnknownSender- Must betrue
giftClaimFromLink
pbgift:v1:... claim link without a server lookup first.
Parameters:
link- Apbgift:v1:...claim linkacknowledgeUnknownSender- Must betrue
giftRefundByRecord
refundAfterBlock has elapsed.
Parameters:
index- Position ingetGiftRecords()
giftRefund
getPendingGifts
getGiftRecords
decodeGiftLink
pbgift:v1:... claim link into a preview. Synchronous and throwing
— works fully offline, so it does not need withContext(Dispatchers.IO).
Parameters:
link- Apbgift:v1:...claim link
GiftLinkPreview
giftFundSecretBearer(...) also exists. It is a bearer instrument
(whoever holds the link can claim), selected only by that explicit method. See
the concept page before considering it.Gift Types
TransferResult returned by the
fund / claim / refund methods:
Portal
Portal deposit addresses. Android exposes the portal lifecycle as methods onPrivacyBoost — createPortal owns the EIP-7702 delegation and the gasless
registration for you. Low-level portal functions are limited to custodial escape
hatches. See the Portal Deposits guide for the
lifecycle and the concept page for the trust
model and current
limitations.
Instance Methods
publishPortalRegistry
withContext(Dispatchers.IO).
Parameters:
portal- The portal deposit addressEindex- The seed-derivation index ofportal
portalDelegateAddress
/info, or null
if the server does not support portals.
Portal lifecycle
createPortal(index)— Derive portalE, gaslessly delegate and register it via the server relays, then publish the discovery entry. Passnullto use the next free derivation index.listPortalsPage(cursor, limit)— One page of the authenticated account’s portals with status and derivation index.limitmust be between 1 and 100; pass the page’snextCursorback ascursorto continue, and treat an absentnextCursoras the final page.listPortalDepositsPage(portal, cursor, limit)— One page of the deposits observed at a portal. Same cursor and limit semantics.getPortalStatus(portal)— Return registry/on-chain status for one portal.sweepPortal(portal, tokenId)— SendrequestPortalDepositfrom the connected wallet and return the transaction hash.reclaimPortalDeposit(depositId)— SendcancelPortalDepositfrom the connected wallet and return the transaction hash.withdrawPortal(...)— Build a signed EIP-1559 transaction that withdraws raw funds resting at seed-derived portalE. Broadcast the returned raw transaction yourself.
Top-Level Functions
These package-level functions are low-level escape hatches for custodial integrations that manage their own portal EOA key. The seed-derivedcreatePortal flow does not expose a private key.
generatePortalEoa()— Generate a fresh portal addressEand its secret private key for custodial integrations.encodePortalWithdraw(token, to, amount)— EncodePortalDelegate.withdrawcalldata for a custodial integration that already controlsE.
Portal Types
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. 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.Instance Methods
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. Suspend, so
call it inside withContext(Dispatchers.IO).
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. Suspend, so call it inside
withContext(Dispatchers.IO).
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 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.
Deposit Cancellation Types
See Also
- Getting Started - Quick start guide
- Wallet Integration - Wallet delegate implementation
- Session Storage - Session persistence
- Claimable Transfers - Gift methods
- Portal Deposits - Portal building blocks
- Multi-Chain - Chain contexts