Privacy Transactions
Use the RP1 SDK to perform private transactions.
Setup
import { RP1Client, Wallet, PrivacyModule } from '@rp1/sdk';
const client = new RP1Client('https://rpc.rp.one');
const wallet = Wallet.fromMnemonic('your mnemonic...');
const privacy = new PrivacyModule(client);
Shield Tokens
Convert public tokens to private:
// Shield 1 RP1
const tx = await privacy.shield(wallet, '1000000', 'urp1');
console.log(`Shielded!`);
console.log(`TX: ${tx.hash}`);
console.log(`Commitment: ${tx.commitment}`);
Get Shielded Balance
// Requires your spending key
const balance = await privacy.getShieldedBalance(wallet);
console.log(`Shielded balance: ${balance.amount} urp1`);
Private Transfer
Transfer without revealing sender, recipient, or amount:
const tx = await privacy.transfer(wallet, 'rp1recipient...', '500000');
console.log(`Private transfer complete!`);
console.log(`TX: ${tx.hash}`);
// Note: On-chain, only nullifier and new commitment are visible
Unshield Tokens
Convert private tokens back to public:
const tx = await privacy.unshield(wallet, '500000', 'urp1');
console.log(`Unshielded!`);
console.log(`TX: ${tx.hash}`);
console.log(`Nullifier: ${tx.nullifier}`);
Viewing Keys
Create Viewing Key
Grant an auditor access to view your transactions:
const tx = await privacy.createViewingKey(wallet, {
grantee: 'rp1auditor...',
type: 'full', // or 'incoming', 'outgoing', 'balance'
expiresAt: '2025-12-31T23:59:59Z',
});
console.log(`Viewing key created!`);
View Key Types
type ViewingKeyType =
| 'full' // See everything
| 'incoming' // See incoming only
| 'outgoing' // See outgoing only
| 'balance'; // See balance only
Revoke Viewing Key
const tx = await privacy.revokeViewingKey(wallet, 'rp1auditor...');
console.log(`Viewing key revoked!`);
List Viewing Keys
const grants = await privacy.getViewingKeyGrants(wallet.address);
grants.forEach(grant => {
console.log(`Grantee: ${grant.grantee}`);
console.log(`Type: ${grant.type}`);
console.log(`Expires: ${grant.expiresAt}`);
});
Use Viewing Key (Auditor)
// As an auditor with a viewing key
const viewingKey = 'viewing_key_from_grantor...';
const history = await privacy.viewTransactions(
'rp1owner...',
viewingKey
);
history.forEach(tx => {
console.log(`Type: ${tx.type}`);
console.log(`Amount: ${tx.amount}`);
console.log(`Time: ${tx.timestamp}`);
});
Complete Privacy Flow
async function privatePayment() {
const privacy = new PrivacyModule(client);
// 1. Check public balance
const publicBalance = await client.getBalance(wallet.address, 'urp1');
console.log(`Public balance: ${publicBalance.amount}`);
// 2. Shield tokens
console.log('Shielding tokens...');
await privacy.shield(wallet, '10000000', 'urp1');
// 3. Wait for confirmation
await new Promise(resolve => setTimeout(resolve, 2000));
// 4. Check shielded balance
const shieldedBalance = await privacy.getShieldedBalance(wallet);
console.log(`Shielded balance: ${shieldedBalance.amount}`);
// 5. Private transfer to recipient
console.log('Sending private transfer...');
const transferTx = await privacy.transfer(
wallet,
'rp1recipient...',
'5000000'
);
console.log(`Private transfer: ${transferTx.hash}`);
// 6. Check remaining shielded balance
const remaining = await privacy.getShieldedBalance(wallet);
console.log(`Remaining shielded: ${remaining.amount}`);
// 7. Unshield remaining
console.log('Unshielding remaining...');
await privacy.unshield(wallet, remaining.amount, 'urp1');
// 8. Check final public balance
const finalBalance = await client.getBalance(wallet.address, 'urp1');
console.log(`Final public balance: ${finalBalance.amount}`);
}
Shielded DEX Swap
import { DEXModule } from '@rp1/sdk';
const dex = new DEXModule(client);
// Execute private swap
const tx = await dex.shieldedSwap(wallet, {
poolId: '1',
tokenIn: 'urp1',
amountIn: '1000000',
minTokenOut: '980000',
});
// On-chain, only ZK proof is visible
// Amount, tokens, and trader are hidden
console.log(`Shielded swap: ${tx.hash}`);
Notes Storage
Private notes are stored locally and encrypted:
// Export notes (backup)
const notesBackup = await privacy.exportNotes(wallet, 'encryption_password');
console.log('Save this backup:', notesBackup);
// Import notes (restore)
await privacy.importNotes(wallet, notesBackup, 'encryption_password');
Best Practices
1. Wait Between Operations
// Let transactions settle before next operation
await privacy.shield(wallet, amount, denom);
await new Promise(r => setTimeout(r, 3000));
await privacy.transfer(wallet, recipient, amount);
2. Use Standard Amounts
// Better for anonymity - use round numbers
await privacy.shield(wallet, '1000000', 'urp1'); // Good
await privacy.shield(wallet, '1234567', 'urp1'); // Less anonymous
3. Backup Notes Regularly
// After each shield/transfer, backup notes
const backup = await privacy.exportNotes(wallet, password);
// Store securely
4. Handle Errors
try {
await privacy.transfer(wallet, recipient, amount);
} catch (error) {
if (error.message.includes('nullifier spent')) {
console.log('Note already spent - sync your wallet');
await privacy.syncNotes(wallet);
}
}