Skip to main content

Private Transfers

This guide covers sending tokens privately between privacy addresses using the Privacy Boost React SDK.

Basic Transfer

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

function TransferButton() {
  const { send } = useVault();

  const handleTransfer = async () => {
    const result = await send({
      to: '0x04...recipient-privacy-address',
      tokenAddress: '0x...token-address',
      amount: '1.0',
    });

    console.log('Transfer request:', result.requestId);
  };

  return <button onClick={handleTransfer}>Send</button>;
}

Transfer Parameters

ParameterTypeRequiredDescription
toHex | stringYesRecipient’s privacy address
tokenAddressHexYesToken contract address
amountstring | bigintYesAmount (human-readable string or wei)

Privacy Address Validation

import { isValidPrivacyAddress } from '@testinprod-io/privacy-boost';

function TransferForm() {
  const { send } = useVault();
  const [recipient, setRecipient] = useState('');
  const [error, setError] = useState('');

  const handleTransfer = async () => {
    if (!isValidPrivacyAddress(recipient)) {
      setError('Invalid privacy address');
      return;
    }

    await send({ to: recipient, tokenAddress: '0x...', amount: '1.0' });
  };

  // ...
}

Complete Example

import { useState } from 'react';
import { useVault, useBalances } from '@testinprod-io/privacy-boost-react';
import { isValidPrivacyAddress } from '@testinprod-io/privacy-boost';

function TransferForm({ tokenAddress }: { tokenAddress: string }) {
  const { send } = useVault();
  const { refresh } = useBalances();
  const [recipient, setRecipient] = useState('');
  const [amount, setAmount] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleTransfer = async () => {
    if (!isValidPrivacyAddress(recipient)) {
      setError('Invalid privacy address');
      return;
    }

    setLoading(true);
    setError(null);

    try {
      await send({ to: recipient, tokenAddress, amount });
      setRecipient('');
      setAmount('');
      await refresh();
    } catch (err: any) {
      if (err.code !== 'TRANSACTION_REJECTED') {
        setError(err.message);
      }
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={recipient}
        onChange={(e) => setRecipient(e.target.value)}
        placeholder="Recipient privacy address"
        disabled={loading}
      />
      <input
        type="text"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
        placeholder="Amount"
        disabled={loading}
      />
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button onClick={handleTransfer} disabled={loading || !recipient || !amount}>
        {loading ? 'Sending...' : 'Send'}
      </button>
    </div>
  );
}

Error Handling

try {
  await send({ to: recipient, tokenAddress, amount });
} catch (error: any) {
  switch (error.code) {
    case 'TRANSACTION_REJECTED':
      return;
    case 'INSUFFICIENT_BALANCE':
      setError('Not enough shielded balance');
      break;
    case 'INVALID_RECIPIENT':
      setError('Invalid privacy address');
      break;
    default:
      setError(error.message);
  }
}

Best Practices

1. Validate Inputs Before Sending

Always validate the privacy address before attempting a transfer.

2. Refresh After Transfer

await send({ to: recipient, tokenAddress, amount });
await refresh();

Next Steps