Skip to main content

Multi-Chain

This guide covers using ChainContextHandle to operate on multiple blockchains from a single iOS SDK instance.
For an overview of multi-chain concepts, see Multi-Chain Concepts. The same identity keys and privacy address apply on every chain.

Setup

Initialize the parent SDK against your primary chain, then open a chain context for each additional chain:
serverUrl and chainId are the only fields you have to give: an omitted contract address is discovered from that chain’s server, and timeoutMs defaults to the SDK-wide 30s. A contract address you do pass has to parse, so a typo fails rather than falling back to the server-advertised pool. createChainContext is synchronous and throws if serverUrl is empty or not an HTTPS URL. Every call returns a new handle with its own session, so create each one once and keep it, for example on the actor or object that owns sdk.

Authentication

Each chain context authenticates before it can operate. Authentication reuses the parent SDK’s privacy keys but obtains a chain-specific JWT and registration, so the user signs once per chain:
ChainContextHandle.authenticate(wallet:) takes only a WalletDelegate; the key source and token provider come from the parent SDK. Apps that authenticate through an external identity provider pass that provider’s token as externalToken:.

Operations

Once authenticated, a ChainContextHandle exposes the same per-chain operations as the parent SDK.

Deposits

Private Transfers

Withdrawals

Balances

Status Polling and History

What the Handle Carries

A handle covers the operations whose state is per chain: shield, prepareShield, unshield, send and sendBatch, unwrapWeth, consolidateNotes, balances and the token catalog, fees, status polling, history and unspent notes, pending-transaction tracking (including waitForPreconfirmation and waitForFinality), and the claimable-transfer (gift) methods. It does not carry portal deposits, earn and swap, audit, or the private treasury (contacts and labels). Those stay on the parent PrivacyBoost, as do resolveIdentity, parseAmount, formatAmount, address validation, setChainReader, and session export. The parent’s pending transactions and token registry reflect its own chain only, so read each chain’s pending transactions and balances through that chain’s handle rather than the parent. The handle has no vault of its own: it shares the parent’s resident keys, so lock() and the auto-lock timers on the parent apply to it as well. Its JWT is separate, which is why clearSession() on the parent does not reach it.

Cross-Chain Patterns

Parallel Operations

Chain contexts are independent, so fan out with async let:

Aggregating Balances

For amounts that exceed UInt64, use BigInt from a library such as BigInt.

Chain Selection

Cleanup

Each chain context can drop its JWT independently while the parent SDK identity stays intact:

Next Steps