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.
Withdrawals
This guide covers withdrawing tokens from your private balance back to a wallet address using the Privacy Boost React Native SDK.
Basic Withdrawal
import { PrivacyBoost } from '@sunnyside-io/privacy-boost-react-native';
const result = await sdk.unshield(
'0x...token-address',
'500000000000000000', // 0.5 tokens
'0x...recipient-address'
);
console.log('Withdraw TX:', result.txHash);
Withdrawal Parameters
| Parameter | Type | Required | Description |
|---|
tokenAddress | string | Yes | ERC-20 token contract address |
amount | string | Yes | Amount in wei (smallest unit) |
recipient | string | Yes | Recipient Ethereum address |
Withdrawal Result
interface UnshieldResult {
txHash: string; // Transaction hash
fee: string; // Fee paid (in wei)
}
Withdraw to Self
The most common case — withdraw to the connected wallet:
const walletAddress = sdk.getWalletAddress();
if (walletAddress) {
const result = await sdk.unshield(tokenAddress, amount, walletAddress);
console.log('Withdraw TX:', result.txHash);
}
Complete Example
import React, { useState } from 'react';
import { View, Text, TextInput, Button, ActivityIndicator } from 'react-native';
import { SdkError } from '@sunnyside-io/privacy-boost-react-native';
function WithdrawScreen({ sdk, tokenAddress }: { sdk: PrivacyBoost; tokenAddress: string }) {
const [amount, setAmount] = useState('');
const [recipient, setRecipient] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleUnshield = async () => {
const target = recipient || sdk.getWalletAddress();
if (!target) return;
setLoading(true);
setError(null);
try {
const weiAmount = sdk.parseAmount(amount, 18);
const result = await sdk.unshield(tokenAddress, weiAmount, target);
console.log('Withdraw TX:', result.txHash);
setAmount('');
} catch (err: any) {
if (SdkError.SignatureRejected.instanceOf(err)) return;
setError(err?.inner?.message ?? err?.message ?? 'Withdrawal failed');
} finally {
setLoading(false);
}
};
return (
<View style={{ padding: 16 }}>
<TextInput
value={amount}
onChangeText={setAmount}
placeholder="Amount (e.g. 0.5)"
keyboardType="decimal-pad"
editable={!loading}
/>
<TextInput
value={recipient}
onChangeText={setRecipient}
placeholder="Recipient (leave empty for self)"
editable={!loading}
/>
{error && <Text style={{ color: 'red' }}>{error}</Text>}
{loading ? (
<ActivityIndicator />
) : (
<Button title="Withdraw" onPress={handleUnshield} disabled={!amount} />
)}
</View>
);
}
Error Handling
try {
const result = await sdk.unshield(tokenAddress, amount, recipient);
} catch (error: any) {
switch (error.tag) {
case 'SignatureRejected':
return;
case 'InsufficientBalance':
console.log('Not enough shielded balance');
break;
case 'InvalidAddress':
console.log('Invalid recipient address');
break;
case 'NetworkError':
console.log('Network error:', error.message);
break;
default:
console.log('Withdrawal error:', error);
}
}
Best Practices
1. Default to Self-Withdrawal
Pre-fill the recipient with the connected wallet address for the most common use case.
2. Refresh Balance After Withdrawal
const result = await sdk.unshield(tokenAddress, amount, recipient);
const updatedBalance = await sdk.getBalance(tokenAddress);
console.log('Remaining shielded:', updatedBalance.shieldedBalance);
3. Show Proof Generation State
Withdrawals require zero-knowledge proof generation which takes time. Always show a loading indicator.
Next Steps