For quick testing, generate an in-memory keypair. For production, see Wallet Adapters.
Copy
import { createInMemorySigner } from "@umbra-privacy/sdk";// Generate a random keypair (for testing only)const signer = await createInMemorySigner();console.log("Wallet address:", signer.address);
An in-memory keypair is ephemeral - it disappears when your process exits. Use a browser wallet or a persistent keypair for anything beyond local testing.
The Umbra program address is different on devnet and mainnet. The SDK resolves the correct address automatically based on the network parameter.
Client construction is synchronous and instant. The wallet signing prompt does not appear until an operation requires the master seed - typically at your first register() or deposit() call.
Registration sets up your on-chain Umbra identity. This function can be called regardless of whether the user is already registered - it handles the full setup, including key rotation when keys have changed. That said, each call submits on-chain transactions with SOL costs, so in practice you should check whether the account is already registered before calling it.
Copy
import { getUserRegistrationFunction } from "@umbra-privacy/sdk";const register = getUserRegistrationFunction({ client });// This is where the wallet signing prompt appears for the first time.// The user signs once to derive the master seed; subsequent operations// reuse the cached seed without prompting again.const signatures = await register({ confidential: true, // enable encrypted balances anonymous: true, // enable mixer / anonymous transfers});console.log(`Registered in ${signatures.length} transaction(s)`);
Send tokens privately to a recipient by depositing them into the mixer. The recipient can later claim them with no on-chain link back to you as the sender.
UTXO creation requires a zkProver dependency for Groth16 proof generation. Install @umbra-privacy/web-zk-prover for the recommended browser-based prover - see ZK Provers for details.
As the recipient, scan the Merkle tree for UTXOs addressed to your X25519 key. The SDK attempts to decrypt each ciphertext and returns only those belonging to you.
Copy
import { getFetchClaimableUtxosFunction } from "@umbra-privacy/sdk";const fetchUtxos = getFetchClaimableUtxosFunction({ client });// Scan tree 0 from the start - pass your last seen index to resumeconst { receiver } = await fetchUtxos(0, 0);console.log("Received UTXOs:", receiver.length);
Present a ZK proof on-chain to burn the UTXO and receive the tokens. Claiming into an encrypted balance keeps the received amount private - no on-chain trace of who received what.
Copy
import { getClaimReceiverClaimableUtxoIntoEncryptedBalanceFunction, getUmbraRelayer,} from "@umbra-privacy/sdk";import { getClaimReceiverIntoEtaProver } from "@umbra-privacy/web-zk-prover";const zkProver = getClaimReceiverIntoEtaProver();const relayer = getUmbraRelayer({ apiEndpoint: "https://6yn4ndrv2i.execute-api.eu-central-1.amazonaws.com",});const claim = getClaimReceiverClaimableUtxoIntoEncryptedBalanceFunction( { client }, { zkProver, relayer },);const result = await claim([receiver[0]]);console.log("Claimed into encrypted balance:", result.signatures);