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.
Getting Started
This guide walks you through integrating the Privacy Boost React Native SDK into your app.
Prerequisites
Overview
The React Native SDK follows a simple flow:
- Initialize - Create SDK instance with configuration
- Authenticate - Connect wallet and authenticate via
WalletDelegate
- Use - Deposit, unshield, transfer tokens
Basic Setup
1. Import the SDK
import { PrivacyBoost } from '@sunnyside-io/privacy-boost-react-native';
import {
PrivacyBoost,
PrivacyBoostConfig,
} from '@sunnyside-io/privacy-boost-react-native';
const config = PrivacyBoostConfig.create({
serverUrl: 'https://test-api.privacyboost.io',
chainId: undefined, // optional; discovered from server
shieldContractAddress: undefined, // optional; discovered from server
wethContractAddress: '0x4200000000000000000000000000000000000006',
appId: 'app_abc123xyz',
teePublicKey: undefined, // optional; discovered from server
persistenceStorage: undefined, // see "Session Persistence" below
persistenceUnlock: undefined,
});
PrivacyBoostConfig.create() validates the fields and fills in defaults. Only
serverUrl and appId are required — chainId, shieldContractAddress, and
teePublicKey are automatically discovered from the server if omitted.
Passing undefined explicitly is required for nullable fields because the
generated types declare them as required-but-nullable.
3. Initialize
try {
const sdk = new PrivacyBoost(config);
} catch (error) {
console.error('Failed to initialize SDK:', error);
}
Connecting a Wallet
The SDK uses the WalletDelegate interface to interact with wallets. You must implement this interface:
import type { WalletDelegate } from '@sunnyside-io/privacy-boost-react-native';
const walletDelegate: WalletDelegate = {
getAddress: async (): Promise<string> => {
// Return the connected wallet address
return '0x...';
},
getChainId: async (): Promise<bigint> => {
// Return the current chain ID
return BigInt(1);
},
signMessage: async (message: string): Promise<string> => {
// Sign using EIP-191 personal_sign
// Return signature as hex string with 0x prefix
return '0x...';
},
signTypedData: async (typedDataJson: string): Promise<string> => {
// Sign using EIP-712 eth_signTypedData_v4
return '0x...';
},
sendTransaction: async (
toAddress: string,
value: string,
data: string
): Promise<string> => {
// Submit transaction and return hash
return '0x...';
},
waitForTransactionReceipt: async (txHash: string) => {
// Poll for the receipt. Return { txHash, status, logs }.
// `status` is true for success. `logs` is an array of { address, topics, data }.
return { txHash, status: true, logs: [] };
},
};
You can use any React Native web3 library (such as ethers.js, viem, or WalletConnect) to implement this delegate.
Then authenticate. authenticate() returns a tagged union with four possible
outcomes — you must handle each:
import { KeySource } from '@sunnyside-io/privacy-boost-react-native';
try {
// Default: wallet-derived keys. Also accepts:
// new KeySource.Mnemonic('twelve word seed phrase ...')
// new KeySource.RawSeed('0xdeadbeef...')
const result = await sdk.authenticate(
walletDelegate,
new KeySource.WalletDerived(),
undefined // optional TokenProvider for app auth
);
switch (result.tag) {
case 'Authenticated':
// Returning user.
console.log('Privacy Address:', result.loginResult.privacyAddress);
console.log('MPK:', result.loginResult.mpk);
console.log('Is new user:', result.loginResult.isNewUser);
break;
case 'MnemonicGenerated':
// First-time user — SDK generated a recovery phrase. Show it to the
// user, have them confirm they've saved it, then continue:
console.log('Save this phrase:', result.mnemonic);
const loginResult = await sdk.proceedAfterMnemonic(undefined);
console.log('Privacy Address:', loginResult.privacyAddress);
break;
case 'CredentialRequired':
// Persistence with PIN/password/biometric/passkey unlock is configured.
// Prompt the user for their credential, then:
const credentialResult = await sdk.submitCredential(credential, undefined);
console.log('Privacy Address:', credentialResult.privacyAddress);
break;
case 'RecoveryRequired':
// Device storage is inconsistent — account exists but local keys are
// missing. Prompt the user to enter their recovery mnemonic and
// re-authenticate with KeySource.Mnemonic.
console.log('Recovery needed:', result.challenge.reason);
break;
}
} catch (error) {
console.error('Authentication failed:', error);
}
CredentialRequired only fires when persistence with PIN/password/biometric
unlock is configured (see the persistenceUnlock field on PrivacyBoostConfig).
For the simple case (no persistence), authenticate() returns Authenticated
(returning user) or MnemonicGenerated (first-time user) directly.
App Authentication (TokenProvider)
If your backend issues app-level auth tokens, implement TokenProvider and
pass it to authenticate():
import type {
TokenProvider,
TokenResponse,
} from '@sunnyside-io/privacy-boost-react-native';
const tokenProvider: TokenProvider = {
async getToken(loginPayloadJson: string): Promise<TokenResponse> {
const resp = await fetch('https://your-backend/auth', {
method: 'POST',
body: loginPayloadJson,
});
const { token, expiresIn } = await resp.json();
return { token, expiresIn: BigInt(expiresIn) };
},
};
await sdk.authenticate(walletDelegate, new KeySource.WalletDerived(), tokenProvider);
Core Operations
Check Balance
try {
const balance = await sdk.getBalance('0x...');
console.log('Shielded:', balance.shieldedBalance);
console.log('Wallet:', balance.walletBalance);
} catch (error) {
console.error('Failed to get balance:', error);
}
Deposit Tokens
Move tokens from wallet to shielded pool:
try {
const result = await sdk.shield(
'0x...', // token address
'1000000000000000000' // 1 token (18 decimals)
);
console.log('Deposit TX:', result.txHash);
console.log('Commitment:', result.commitment);
console.log('Request ID:', result.requestId);
if (result.wrapTxHash) {
console.log('Wrap TX (ETH→WETH):', result.wrapTxHash);
}
} catch (error) {
console.error('Deposit failed:', error);
}
Use requestId with sdk.getShieldStatus(requestId) to poll the shield’s
finality state. wrapTxHash is only present when depositing native ETH (the
SDK wraps to WETH first).
Withdraw Tokens
Move tokens from shielded pool to wallet:
try {
const result = await sdk.unshield(
'0x...', // token address
'500000000000000000', // amount
'0x...' // recipient address
);
console.log('Withdraw TX:', result.txHash);
} catch (error) {
console.error('Withdraw failed:', error);
}
Private Transfer
Send tokens privately to another user:
try {
const result = await sdk.send(
'0x...', // token address
'250000000000000000', // amount
'0x04...' // 194-char privacy address
);
console.log('Transfer TX:', result.txHash);
} catch (error) {
console.error('Transfer failed:', error);
}
Error Handling
The SDK throws SDKError for various failure conditions:
import { SdkError, SdkError_Tags } from '@sunnyside-io/privacy-boost-react-native';
try {
const result = await sdk.shield(tokenAddress, amount);
} catch (error) {
// SdkError is a tagged union. Each variant is a class you can instanceof-check.
if (SdkError.NotConnected.instanceOf(error)) {
console.log('Wallet not connected');
} else if (SdkError.NotAuthenticated.instanceOf(error)) {
console.log('Not logged in');
} else if (SdkError.InsufficientBalance.instanceOf(error)) {
console.log('Insufficient balance');
} else if (SdkError.InvalidAmount.instanceOf(error)) {
console.log('Invalid amount format');
} else if (SdkError.WalletError.instanceOf(error)) {
console.log('Wallet error:', (error as any).inner?.message);
} else if (SdkError.NetworkError.instanceOf(error)) {
console.log('Network error:', (error as any).inner?.message);
} else {
console.log('Unknown error:', error);
}
}
Session Persistence
Save and restore sessions to avoid re-signing:
import AsyncStorage from '@react-native-async-storage/async-storage';
// Export session
const session = sdk.exportSession();
if (session) {
await AsyncStorage.setItem('privacy_session', JSON.stringify(session));
}
// Import session
const stored = await AsyncStorage.getItem('privacy_session');
if (stored) {
try {
const session = JSON.parse(stored);
const success = sdk.importSession(session);
if (success) {
console.log('Session restored');
}
} catch (error) {
console.log('Session expired or invalid');
}
}
Next Steps
Deposits
Deposit tokens into the shielded pool
Withdrawals
Withdraw tokens from the shielded pool
Private Transfers
Send tokens privately between users
Balances
Query and display token balances
Transaction History
View and filter transaction history
Wallet Integration
Connect wallets and authenticate
Session Storage
Secure persistence with AsyncStorage and Keychain
Error Handling
Error codes and recovery patterns