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

# Deposits

# Deposits

This guide covers depositing tokens from your wallet into your private balance using the Privacy Boost React Native SDK.

## Basic Deposit

```typescript theme={null}
import { PrivacyBoost } from '@sunnyside-io/privacy-boost-react-native';

const result = await sdk.shield(
  '0x...token-address',
  '1000000000000000000' // 1 token (18 decimals)
);
console.log('Transaction hash:', result.txHash);
console.log('Commitment:', result.commitment);
```

## Deposit Parameters

| Parameter      | Type     | Required | Description                   |
| -------------- | -------- | -------- | ----------------------------- |
| `tokenAddress` | `string` | Yes      | ERC-20 token contract address |
| `amount`       | `string` | Yes      | Amount in wei (smallest unit) |

## Deposit Steps

When a deposit is submitted, the SDK executes these steps in order:

| Step        | Description                                     |
| ----------- | ----------------------------------------------- |
| Wrapping    | Wrapping ETH to WETH (if depositing ETH)        |
| Approving   | Approving token spending on the shield contract |
| Shielding   | Executing the deposit transaction               |
| Registering | Registering the deposit with the indexer        |
| Compliance  | Waiting for compliance verification             |

## Deposit Result

```typescript theme={null}
interface ShieldResult {
  txHash: string;        // Main shield transaction hash
  commitment: string;    // Note commitment
  requestId: string;     // Use with sdk.getShieldStatus(requestId) to poll finality
  warning?: string;      // Optional warning message
  wrapTxHash?: string;   // ETH→WETH wrap tx hash (only for native ETH shields)
}
```

Poll the shield's status with `sdk.getShieldStatus(result.requestId)` until
it reaches a terminal state (e.g. `"confirmed"` or `"failed"`).

## Depositing ETH

To deposit native ETH, use the zero address. The SDK automatically wraps ETH to WETH:

```typescript theme={null}
const ethAddress = '0x0000000000000000000000000000000000000000';

const result = await sdk.shield(
  ethAddress,
  '1000000000000000000' // 1 ETH
);
console.log('Deposit tx:', result.txHash);
```

The SDK automatically:

1. Wraps ETH to WETH
2. Approves WETH spending
3. Deposits WETH to the shield contract

## Parsing Amounts

Use helper functions to convert between human-readable and wei formats:

```typescript theme={null}
// Parse human-readable amount to wei string
const weiAmount = sdk.parseAmount('1.5', 18);
// Returns: "1500000000000000000"

// Format wei string to human-readable
const formatted = sdk.formatAmount('1500000000000000000', 18);
// Returns: "1.5"

// For USDC (6 decimals)
const usdcWei = sdk.parseAmount('100.0', 6);
// Returns: "100000000"
```

## 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 DepositScreen({ sdk, tokenAddress }: { sdk: PrivacyBoost; tokenAddress: string }) {
  const [amount, setAmount] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [txHash, setTxHash] = useState<string | null>(null);

  const handleShield = async () => {
    setLoading(true);
    setError(null);
    setTxHash(null);

    try {
      const weiAmount = sdk.parseAmount(amount, 18);
      const result = await sdk.shield(tokenAddress, weiAmount);
      setTxHash(result.txHash);
      setAmount('');
    } catch (err: any) {
      if (SdkError.SignatureRejected.instanceOf(err)) return;
      setError(err?.inner?.message ?? err?.message ?? 'Deposit failed');
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={{ padding: 16 }}>
      <TextInput
        value={amount}
        onChangeText={setAmount}
        placeholder="Amount (e.g. 1.0)"
        keyboardType="decimal-pad"
        editable={!loading}
      />
      {error && <Text style={{ color: 'red' }}>{error}</Text>}
      {txHash && <Text>Deposit TX: {txHash}</Text>}
      {loading ? (
        <ActivityIndicator />
      ) : (
        <Button title="Deposit" onPress={handleShield} disabled={!amount} />
      )}
    </View>
  );
}
```

## Error Handling

```typescript theme={null}
try {
  const result = await sdk.shield(tokenAddress, amount);
} catch (error: any) {
  switch (error.tag) {
    case 'SignatureRejected':
      return; // User cancelled
    case 'InsufficientBalance':
      console.log('Not enough tokens in wallet');
      break;
    case 'InvalidAmount':
      console.log('Invalid amount format');
      break;
    case 'WalletError':
      console.log('Wallet error:', error.message);
      break;
    case 'NetworkError':
      console.log('Network error:', error.message);
      break;
    default:
      console.log('Deposit error:', error);
  }
}
```

## Best Practices

### 1. Validate Amounts Before Depositing

Always check the wallet balance before attempting a deposit to provide early feedback.

### 2. Refresh Balance After Deposit

```typescript theme={null}
const result = await sdk.shield(tokenAddress, amount);
const updatedBalance = await sdk.getBalance(tokenAddress);
console.log('New shielded balance:', updatedBalance.shieldedBalance);
```

### 3. Handle Long Operations

Deposits involve multiple on-chain transactions and may take time. Show appropriate loading states in your UI.

## Relayed Deposits (build calldata, relay yourself)

If your users don't submit transactions directly — they hold funds at addresses
you relay for (a gasless relayer, an EIP-7702 session key, a custom pipeline) —
build the deposit calldata without submitting it, relay it through your own
infrastructure, then finalize from the mined receipt.

```typescript theme={null}
// 1. Build the calldata (nothing submitted)
const prepared = await sdk.prepareShield(
  '0x...',
  '1000000000000000000',
  undefined // pass a privacy address to shield to someone else
);

// prepared.wrap / prepared.approve / prepared.shield are { to, value, data }
// calls — relay them in order (wrap?, approve?, shield).
const calls = [prepared.wrap, prepared.approve, prepared.shield].filter(Boolean);
const receipt = await myRelayer.submit(calls);

// 2. Finalize from the mined receipt to recover the request id
const result = finalizeShield(
  receipt,
  prepared.finalize.shieldContract,
  prepared.commitment
);
console.log('Request ID:', result.requestId);
```

Each call is `{ to, value, data }`, so the array drops directly into an
EIP-5792 / Porto `wallet_prepareCalls` bundle.

### Server-side (no session)

A backend that holds only a recipient's privacy address can build a deposit on
their behalf with the stateless `buildShieldPayload` named export — no signed-in
session and no private keys:

```typescript theme={null}
import { buildShieldPayload } from '@sunnyside-io/privacy-boost-react-native';

const prepared = buildShieldPayload(
  '0x...',
  '1000000000000000000',
  userPrivacyAddress,
  tokenId,                 // from the token catalog
  shieldContractAddress,
  undefined,               // wethContractAddress — required only for native ETH
  teePublicKey,
  minShieldAmount,         // optional: reject below the per-token minimum, or undefined
  true,                    // emitApprove
);
```

The note's owner is bound cryptographically to the recipient's privacy address,
so only they can spend it; the ephemeral sender used to encrypt the deposit is
generated and discarded internally.

## Next Steps

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