Client API
createUPPClient — the main entry point for shielding, transferring, and withdrawing tokens.
createUPPClient
The main entry point for UPP operations.
import { createUPPClient } from '@permissionless-technologies/upp-sdk'
const upp = await createUPPClient({
publicClient, // viem PublicClient
walletClient, // viem WalletClient (connected to user's wallet)
chainId?, // optional — defaults to walletClient.chain.id
rpcUrl?, // optional — custom RPC for note indexing
})On creation, the SDK prompts the user's wallet for a signature to derive their private keys. No key material leaves the browser.
Methods
upp.shield(params)
Deposit ERC20 tokens into the privacy pool.
const { commitment, txHash } = await upp.shield({
token: Address, // ERC20 token contract address
amount: bigint, // Amount in token's smallest unit
proofSystem?: 'snark' | 'stark', // default: 'snark'
})| Returns | Type | Description |
|---|---|---|
commitment | Hex | On-chain note commitment |
txHash | Hex | Transaction hash |
upp.transfer(params)
Send privately to another user. Consumes one note, creates two (recipient + change).
const { recipientCommitment, changeCommitment, txHash } = await upp.transfer({
amount: bigint, // Amount to send
to: string, // Recipient's stealth meta-address (0zk1...)
note?: Note, // Specific note to spend (optional — SDK picks one)
proofSystem?: 'snark' | 'stark',
})upp.withdraw(params) / upp.unshield(params)
Exit the pool to a public address.
const { txHash } = await upp.withdraw({
amount: bigint, // Amount to withdraw
to: Address, // Recipient public address
aspId: bigint, // ASP ID to use for compliance proof
note?: Note, // Specific note to spend (optional)
})Ragequit
If your origin is not in any ASP, you can still withdraw to your own address (the original depositor address). The SDK handles this automatically when to === origin.
upp.merge(params)
Combine two notes into one. The caller becomes the new origin.
const { commitment, txHash } = await upp.merge({
notes: [note1, note2], // Exactly 2 notes to merge
})upp.scan()
Scan the blockchain for notes belonging to this account.
const notes = await upp.scan()
// Returns Note[] — all notes (including spent)
const unspent = notes.filter(n => !n.spent)
const balance = unspent.reduce((sum, n) => sum + n.amount, 0n)upp.getNotes()
Return cached notes (from last scan, without re-scanning).
const notes = upp.getNotes()upp.getStealthMetaAddress()
Get your stealth meta-address to share with senders.
const stealthAddress = upp.getStealthMetaAddress()
// '0zk1sepolia1...'upp.exportViewingKeys(params)
Export viewing keys for specific notes (for auditors).
const auditExport = await upp.exportViewingKeys({
notes: [note1, note2],
})
// Send auditExport to auditor — they can decrypt these notes onlyupp.approve(params)
Approve the UPP contract to spend tokens (required before shield).
await upp.approve({
token: Address,
amount: bigint,
})Note Type
interface Note {
amount: bigint
token: Address
commitment: Hex
nullifier: Hex
leafIndex: number
spent: boolean
blinding: bigint
origin: Address
sender: Address
}