Skip to main content

Private Transfers

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

Basic Transfer

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

const result = await sdk.send(
  '0x...token-address',
  '250000000000000000', // 0.25 tokens
  '0x04...recipient-privacy-address' // 194-char privacy address
);
console.log('Transfer TX:', result.txHash);

Transfer Parameters

ParameterTypeRequiredDescription
tokenAddressstringYesToken contract address
amountstringYesAmount in wei (smallest unit)
recipientPrivacyAddressstringYesRecipient’s 194-character privacy address

Transfer Result

interface TransferResult {
  txHash: string;  // Transaction hash
  fee: string;     // Fee paid (in wei)
}

Privacy Address Validation

Always validate the recipient’s privacy address before sending:
const isValid = sdk.isValidPrivacyAddress(recipientAddress);
if (!isValid) {
  console.log('Invalid privacy address');
  return;
}

const result = await sdk.send(tokenAddress, amount, recipientAddress);

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

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

    setLoading(true);
    setError(null);

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

  return (
    <View style={{ padding: 16 }}>
      <TextInput
        value={recipient}
        onChangeText={setRecipient}
        placeholder="Recipient privacy address"
        editable={!loading}
      />
      <TextInput
        value={amount}
        onChangeText={setAmount}
        placeholder="Amount (e.g. 1.0)"
        keyboardType="decimal-pad"
        editable={!loading}
      />
      {error && <Text style={{ color: 'red' }}>{error}</Text>}
      {loading ? (
        <ActivityIndicator />
      ) : (
        <Button
          title="Send"
          onPress={handleTransfer}
          disabled={!recipient || !amount}
        />
      )}
    </View>
  );
}

Error Handling

try {
  await sdk.send(tokenAddress, amount, recipientPrivacyAddress);
} catch (error: any) {
  switch (error.tag) {
    case 'SignatureRejected':
      return;
    case 'InsufficientBalance':
      console.log('Not enough shielded balance');
      break;
    case 'InvalidAddress':
      console.log('Invalid privacy address');
      break;
    case 'NetworkError':
      console.log('Network error:', error.message);
      break;
    default:
      console.log('Transfer error:', error);
  }
}

Best Practices

1. Validate Inputs Before Sending

Always validate the privacy address before attempting a transfer.

2. Refresh After Transfer

await sdk.send(tokenAddress, amount, recipientPrivacyAddress);
const updatedBalance = await sdk.getBalance(tokenAddress);
console.log('Remaining shielded:', updatedBalance.shieldedBalance);

Next Steps