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.
Private Transfers
This guide covers sending tokens privately between privacy addresses.
Basic Transfer
const result = await sdk.vault.send({
to: '0x04...recipient-privacy-address',
tokenAddress: '0x...token-address',
amount: 1000000000000000000n, // 1 token
});
console.log('Transaction hash:', result.txHash);
Transfer Parameters
interface SendParams {
to: PrivacyAddress; // Recipient's privacy address
tokenAddress: Hex; // Token to send
amount: bigint; // Amount in wei
}
| Parameter | Type | Required | Description |
|---|
to | PrivacyAddress | Yes | Recipient’s privacy address |
tokenAddress | Hex | Yes | Token contract address |
amount | bigint | Yes | Amount in smallest unit |
Transfer Result
interface TransactionResult {
txHash: Hex; // Transaction hash
}
Privacy Address Validation
Always validate privacy addresses before sending:
import { isValidPrivacyAddress, validatePrivacyAddress } from '@sunnyside-io/privacy-boost';
// Check if valid
if (!isValidPrivacyAddress(recipientAddress)) {
throw new Error('Invalid privacy address');
}
// Or throw on invalid
validatePrivacyAddress(recipientAddress); // Throws if invalid
// Then send
await sdk.vault.send({
to: recipientAddress,
tokenAddress: '0x...',
amount: 1000000000000000000n,
});
Transfer to MPK
If you have the recipient’s MPK instead of privacy address:
import { encodePrivacyAddress } from '@sunnyside-io/privacy-boost';
// Convert MPK to privacy address
const privacyAddress = encodePrivacyAddress(mpk, viewingKey);
await sdk.vault.send({
to: privacyAddress,
tokenAddress: '0x...',
amount: 1000000000000000000n,
});
Checking Balance Before Transfer
async function safeTransfer(params: SendParams) {
const balance = await sdk.vault.getBalance(params.tokenAddress);
if (params.amount > balance) {
throw new Error(
`Insufficient balance. Have: ${balance}, Need: ${params.amount}`
);
}
return sdk.vault.send(params);
}
Transfer Privacy
Private transfers provide:
- Sender Privacy: Your wallet address is not linked to the transaction
- Recipient Privacy: The recipient’s wallet address is not revealed
- Amount Privacy: The transfer amount is encrypted
- Relationship Privacy: No public link between sender and recipient
Only the sender and recipient can see the transfer details.
Error Handling
try {
await sdk.vault.send(params);
} catch (error) {
switch (error.code) {
case 'INSUFFICIENT_BALANCE':
console.log('Not enough shielded balance');
break;
case 'INVALID_RECIPIENT':
console.log('Invalid privacy address');
break;
case 'INVALID_AMOUNT':
console.log('Invalid amount');
break;
case 'TRANSFER_FAILED':
console.log('Transfer transaction failed');
break;
default:
console.log('Transfer error:', error.message);
}
}
UI Example
import { useState } from 'react';
import { isValidPrivacyAddress } from '@sunnyside-io/privacy-boost';
function TransferForm() {
const [recipient, setRecipient] = useState('');
const [amount, setAmount] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleTransfer = async () => {
setError('');
// Validate recipient
if (!isValidPrivacyAddress(recipient)) {
setError('Invalid privacy address');
return;
}
setLoading(true);
try {
const parsedAmount = parseAmount(amount, decimals);
await sdk.vault.send({
to: recipient,
tokenAddress,
amount: parsedAmount,
});
alert('Transfer successful!');
setRecipient('');
setAmount('');
} catch (err) {
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}>
{loading ? 'Sending...' : 'Send'}
</button>
</div>
);
}
Best Practices
function validateTransferParams(params: SendParams) {
if (!isValidPrivacyAddress(params.to)) {
throw new Error('Invalid recipient privacy address');
}
if (params.amount <= 0n) {
throw new Error('Amount must be positive');
}
if (!isEvmAddress(params.tokenAddress)) {
throw new Error('Invalid token address');
}
}
2. Confirm Large Transfers
async function transferWithConfirmation(params: SendParams) {
const tokenMetadata = await sdk.vault.getToken(params.tokenAddress);
const formattedAmount = formatAmount(
params.amount,
tokenMetadata.decimals
);
const confirmed = confirm(
`Send ${formattedAmount} ${tokenMetadata.symbol} to ${params.to.slice(0, 10)}...?`
);
if (!confirmed) {
throw new Error('Transfer cancelled by user');
}
return sdk.vault.send(params);
}
3. Handle Network Delays
async function transferWithRetry(params: SendParams, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await sdk.vault.send(params);
} catch (error) {
if (attempt === maxRetries) throw error;
if (error.code === 'NETWORK_ERROR') {
await new Promise((r) => setTimeout(r, 2000 * attempt));
continue;
}
throw error;
}
}
}
Next Steps