> ## 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

# Withdrawals

This guide covers withdrawing tokens from your private balance back to a wallet address using the Privacy Boost React Native SDK.

## Basic Withdrawal

```typescript theme={null}
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

```typescript theme={null}
interface UnshieldResult {
  txHash: string;  // Transaction hash
  fee: string;     // Fee paid (in wei)
}
```

## Withdraw to Self

The most common case — withdraw to the connected wallet:

```typescript theme={null}
const walletAddress = sdk.getWalletAddress();
if (walletAddress) {
  const result = await sdk.unshield(tokenAddress, amount, walletAddress);
  console.log('Withdraw TX:', result.txHash);
}
```

## Complete Example

```tsx theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

* [Deposits Guide](./deposits)
* [Transfers Guide](./transfers)
* [Balances Guide](./balances)
* [Error Handling](./error-handling)
