SDK Quickstart
Install the UPP SDK, shield tokens, transfer privately, and withdraw — in under 5 minutes.
Private Preview
The UPP SDK is in private preview. Contact us for early access.
Installation
npm install @permissionless-technologies/upp-sdkSetup
import { createUPPClient } from '@permissionless-technologies/upp-sdk'
import { createWalletClient, createPublicClient, http } from 'viem'
import { sepolia } from 'viem/chains'
const publicClient = createPublicClient({ chain: sepolia, transport: http() })
const walletClient = createWalletClient({ chain: sepolia, transport: http() })
// Initialize UPP client — keys derive from wallet signature (no extra seed phrases)
const upp = await createUPPClient({ publicClient, walletClient })Core Operations
Shield (Deposit)
Move public tokens into the private pool:
import { parseUnits } from 'viem'
// Approve UPP to spend your tokens
await upp.approve({ token: UPD_TOKEN_ADDRESS, amount: parseUnits('1000', 18) })
// Shield tokens — creates an encrypted note in the shared pool
const { commitment } = await upp.shield({
token: UPD_TOKEN_ADDRESS,
amount: parseUnits('1000', 18),
})
console.log('Shielded! Note commitment:', commitment)Transfer (Private Send)
Send to another user within the pool:
// Get recipient's stealth meta-address (they share this publicly)
const recipientAddress = '0zk1sepolia1...'
// Transfer — proves you own the note without revealing which one
const { recipientCommitment, changeCommitment } = await upp.transfer({
amount: parseUnits('500', 18),
to: recipientAddress,
})
// Recipient gets 500 UPD, you get a change noteCheck Balance
Scan for your notes and compute private balance:
// Scans encrypted notes, decrypts yours using your viewing key
const notes = await upp.scan()
const balance = notes
.filter(n => n.token === UPD_TOKEN_ADDRESS && !n.spent)
.reduce((sum, n) => sum + n.amount, 0n)
console.log('Private balance:', balance)Unshield (Withdraw)
Move tokens back to a public address:
const { txHash } = await upp.unshield({
amount: parseUnits('200', 18),
to: '0xRecipientAddress',
aspId: 1n, // Which ASP to use for the compliance proof
})React Integration
import { UPPAccountProvider, useUPPAccount } from '@permissionless-technologies/upp-sdk/react'
function App() {
return (
<UPPAccountProvider>
<PrivateBalance />
</UPPAccountProvider>
)
}
function PrivateBalance() {
const { notes, isScanning, shield, transfer, unshield } = useUPPAccount()
const balance = notes
?.filter(n => !n.spent)
.reduce((sum, n) => sum + n.amount, 0n) ?? 0n
if (isScanning) return <div>Scanning notes...</div>
return (
<div>
<p>Private balance: {balance.toString()}</p>
<button onClick={() => shield({ token: UPD_TOKEN_ADDRESS, amount: parseUnits('100', 18) })}>
Shield 100 UPD
</button>
</div>
)
}Key Concepts
Stealth Addresses
Recipients share a stealth meta-address (0zk1...). Senders derive unique one-time addresses per payment — even the recipient's public address never appears on-chain.
// Generate your stealth meta-address to share publicly
const myStealthAddress = upp.getStealthMetaAddress()Viewing Keys
Export viewing keys for specific notes to give auditors selective read access:
const auditExport = await upp.exportViewingKeys({
notes: [note1, note2], // Only these notes become visible
})
// Send auditExport to auditor — they can decrypt these notes onlyNotes
Each shield or transfer creates notes (encrypted UTXOs). The SDK tracks these automatically:
const notes = await upp.getNotes()
// Each note: { amount, token, commitment, spent, leafIndex }Error Handling
try {
await upp.transfer({ amount, to })
} catch (e) {
if (e.code === 'INSUFFICIENT_BALANCE') {
// Not enough private balance
} else if (e.code === 'ASP_PROOF_FAILED') {
// Origin not in any ASP allowlist — may need to ragequit
} else if (e.code === 'PROOF_GENERATION_FAILED') {
// ZK proof failed — check inputs
}
}Next Steps
- Concepts — Notes and Account Model — how the UTXO model works
- Concepts — ASP Compliance — how compliance proofs work
- SDK Reference — full API documentation
- STARK Vault — post-quantum security deep dive
Universal Private Pool
Privacy layer for any ERC20 token — shared anonymity pool with SNARK and post-quantum STARK proofs, stealth addresses, and compliance-ready ASP verification.
Notes and Account Model
UPP uses a UTXO-style note model instead of account balances — encrypted UTXOs that prove ownership without revealing contents.