Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.privacyboost.io/llms.txt

Use this file to discover all available pages before exploring further.

Multi-Chain

The Android SDK currently does not expose a native chain-context API — PrivacyBoost is initialized against a single chain via its config. Multi-chain support exists in the underlying Rust core and is exposed today on the TypeScript, React Native, and Web/WASM SDKs.
For an architectural overview of how multi-chain identity works, see Multi-Chain Concepts. The same identity keys and privacy address apply across chains regardless of which SDK creates them.

Single-Chain Setup

Pick a chain at SDK init time:
val config = PrivacyBoostConfig(
    serverUrl = "https://op.example.com",
    chainId = 10u,                          // Optimism
    shieldContractAddress = null,           // discovered from server
    wethContractAddress = "0x4200000000000000000000000000000000000006",
    teePublicKey = null,
    appId = "my-app",
    persistenceStorage = null,
    persistenceUnlock = null
)
val sdk = PrivacyBoost(config)
Switching chains is a config swap — tear down the current SDK and instantiate a new one with the new server URL and chainId.

Multiple SDK Instances (Workaround)

If you need to operate on more than one chain in a single app session, you can instantiate one PrivacyBoost per chain. Each instance keeps its own JWT and chain state, but you must authenticate each one separately.
val optimism = PrivacyBoost(PrivacyBoostConfig(
    serverUrl = "https://op.example.com",
    chainId = 10u,
    shieldContractAddress = null,
    wethContractAddress = "0x4200000000000000000000000000000000000006",
    teePublicKey = null,
    appId = "my-app",
    persistenceStorage = null,
    persistenceUnlock = null
))

val ethereum = PrivacyBoost(PrivacyBoostConfig(
    serverUrl = "https://eth.example.com",
    chainId = 1u,
    shieldContractAddress = null,
    wethContractAddress = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    teePublicKey = null,
    appId = "my-app",
    persistenceStorage = null,
    persistenceUnlock = null
))

// Authenticate each instance independently with the same wallet.
optimism.authenticate(
    wallet = walletDelegate,
    keySource = KeySource.WalletDerived(),
    tokenProvider = null,
)
ethereum.authenticate(
    wallet = walletDelegate,
    keySource = KeySource.WalletDerived(),
    tokenProvider = null,
)

Caveats

  • Persistence collisions. Both instances will try to read/write the same Keystore entries if you pass persistenceStorage/persistenceUnlock. Either leave persistence off (null) on the secondary instances, or use distinct appIds — but distinct app IDs mean distinct identities, which defeats the multi-chain story.
  • Re-derivation per chain. Each instance derives keys via the wallet signature and re-issues a JWT, so the user signs once per chain.
  • No cross-instance state. Pending transactions, balances, and history are siloed per instance — your app code must aggregate.
  • No proper resource sharing. The multi-chain ChainContext API on TS/RN/Web shares one identity and only multiplexes the chain JWT; with multiple Android SDK instances you pay the full proving / state init cost on each one.
This pattern is suitable for showing balances or running occasional cross-chain operations. For production multi-chain UX, prefer the chain-context API on the platforms that expose it, or wait for native Android support.

Operating per Chain

Once authenticated, the API surface is identical across instances:
val opAmount = optimism.parseAmount("1.0", decimals = 18u)
val opShield = optimism.shield(
    tokenAddress = "0x4200000000000000000000000000000000000006",
    amount = opAmount,
)

val ethAmount = ethereum.parseAmount("0.5", decimals = 18u)
val ethShield = ethereum.shield(
    tokenAddress = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    amount = ethAmount,
)

Parallel Operations

Use coroutines to fan out:
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope

suspend fun shieldBoth(): Pair<ShieldResult, ShieldResult> = coroutineScope {
    val opTask  = async { optimism.shield(opToken, opAmount) }
    val ethTask = async { ethereum.shield(ethToken, ethAmount) }
    Pair(opTask.await(), ethTask.await())
}

Aggregating Balances

import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.awaitAll
import java.math.BigInteger

data class ChainEntry(val sdk: PrivacyBoost, val token: String)

suspend fun totalShielded(chains: List<ChainEntry>): BigInteger = coroutineScope {
    chains
        .map { entry -> async { entry.sdk.getBalance(entry.token).shieldedBalance } }
        .awaitAll()
        .map { BigInteger(it) }
        .fold(BigInteger.ZERO, BigInteger::add)
}

Roadmap

A native ChainContextHandle for Android — mirroring the React Native and TypeScript surfaces — is planned. When available, it will replace the multi-instance workaround with a single SDK instance that multiplexes JWTs and shares identity keys.

Next Steps