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.

Deposits

This guide covers depositing tokens into the privacy pool using the Privacy Boost React SDK.

Basic Deposit

import { useVault } from '@sunnyside-io/privacy-boost-react';

function ShieldButton() {
  const { shield } = useVault();

  const handleShield = async () => {
    const result = await shield({
      tokenAddress: '0x...token-address',
      amount: '1.0',
    });

    console.log('Deposit tx:', result.txHash);
  };

  return <button onClick={handleShield}>Deposit</button>;
}

Deposit Parameters

ParameterTypeRequiredDescription
tokenAddressHexYesToken contract address
amountstring | bigintYesEither a human-readable decimal string (e.g. "1.5", parsed using the token’s decimals) or a bigint in wei (e.g. 1500000000000000000n).
onProgressOnProgressNoProgress callback (see Progress Tracking).
This differs from the TypeScript SDK, which only accepts bigint (wei), and from the mobile SDKs, which accept a wei-as-string. The React useVault hook normalizes for you: a human-readable string is parsed with the token’s decimals before being passed to the underlying SDK.

Progress Tracking

Track shield steps with the onProgress callback:
function DepositWithProgress() {
  const { shield } = useVault();
  const [step, setStep] = useState<string | null>(null);

  const handleShield = async () => {
    await shield({
      tokenAddress: '0x...token-address',
      amount: '1.0',
      onProgress: ({ step, message }) => {
        setStep(message);
      },
    });
    setStep(null);
  };

  return (
    <div>
      <button onClick={handleShield}>Deposit</button>
      {step && <p>{step}</p>}
    </div>
  );
}

Deposit Steps

The step value comes from the ShieldStep enum and matches the same values across all SDK platforms.
StepDescription
wrappingWrapping native ETH to WETH (only when shielding ETH)
approvingApproving the shield contract to spend the token
shieldingSubmitting the shield transaction on-chain
registeringRegistering the new note with the indexer
complianceAwaiting the compliance check on the deposit

Depositing ETH

Native ETH is automatically wrapped to WETH during shield:
const ETH_ADDRESS = '0x0000000000000000000000000000000000000000';

const result = await shield({
  tokenAddress: ETH_ADDRESS,
  amount: '0.1',
});

Complete Example

import { useState } from 'react';
import { useVault } from '@sunnyside-io/privacy-boost-react';

function ShieldForm({ tokenAddress }: { tokenAddress: string }) {
  const { shield, refreshBalances } = useVault();
  const [amount, setAmount] = useState('');
  const [loading, setLoading] = useState(false);
  const [step, setStep] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

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

    try {
      await shield({
        tokenAddress,
        amount,
        onProgress: ({ message }) => setStep(message),
      });
      setAmount('');
      await refreshBalances();
    } catch (err: any) {
      if (err.code !== 'TRANSACTION_REJECTED') {
        setError(err.message);
      }
    } finally {
      setLoading(false);
      setStep(null);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
        placeholder="Amount"
        disabled={loading}
      />
      {error && <p style={{ color: 'red' }}>{error}</p>}
      {step && <p>{step}</p>}
      <button onClick={handleShield} disabled={loading || !amount}>
        {loading ? 'Depositing...' : 'Deposit'}
      </button>
    </div>
  );
}

Error Handling

try {
  await shield({ tokenAddress, amount });
} catch (error: any) {
  switch (error.code) {
    case 'TRANSACTION_REJECTED':
      return;
    case 'INSUFFICIENT_BALANCE':
      setError('Not enough balance in wallet');
      break;
    case 'INVALID_AMOUNT':
      setError('Invalid amount');
      break;
    default:
      setError(error.message);
  }
}

Best Practices

1. Refresh Balances After Deposit

useBalances() is reactive and will pick up updates the SDK already knows about. Call refreshBalances() (from useVault) to force a server fetch — for example, immediately after a shield, when you want the UI to reflect the new shielded balance without waiting for the next polling tick.
const { shield, refreshBalances } = useVault();

await shield({ tokenAddress, amount });
await refreshBalances();

2. Handle Wallet Rejection Silently

When users cancel the wallet popup, don’t show an error:
try {
  await shield({ tokenAddress, amount });
} catch (err: any) {
  if (err.code === 'TRANSACTION_REJECTED') return;
  setError(err.message);
}

3. Show Progress to Users

Deposits involve multiple on-chain steps. Always show progress so users know the operation is working.

Next Steps