Zolana documentation
Everything you need to send and receive private Solana transfers with Zolana: what each step does, exactly which wallet approvals to expect, and — most importantly — how to get your funds out of any intermediate state.
# Overview
Zolana is a metadata-privacy layer. The on-chain confidentiality (hiding the amount and the recipient of a transfer) is provided by the Umbra protocol — Groth16 zero-knowledge proofs plus Arcium multi-party computation. Zolana's job is everything around that: routing every network request through the Nym mixnet so your IP and request patterns don't betray you, bundling the ZK proving files locally so proving doesn't phone home, scheduling claims and withdrawals with timing jitter, and reporting honestly what is protected against whom.
A full private transfer has four stages, and the app shows all of them live:
# Modes & what's actually private
Zolana ships two profiles. The app banner always tells you which one you're in — and what it means. We never present a test mode as private.
| Profile | Transport | What it's for | Privacy posture |
|---|---|---|---|
| strict-max | Nym mixnet, fail-closed | The real thing: every RPC read, indexer call, relayer submit and MPC poll leaves through the mixnet — or the action is blocked. | On-chain confidentiality + origin-IP protection. Expect seconds per network round-trip; that latency is the privacy. |
| devnet-fast | Direct clearnet | Functional testing of the same on-chain flow with fast feedback. | Not network-private. The on-chain payload is still confidential, but your RPC provider sees your IP and request timing. The app shows a permanent amber warning in this mode. |
# Quickstart
# Sending privately
Split across multiple recipients
The send card has a Split across multiple recipients panel. Paste several addresses (one per line), set a total and a minimum each, and Zolana funds your private balance once for the total, then issues one private note per recipient. Two options, both on by default and both good for privacy:
- Random amounts — the total is split into uneven, non-round amounts (each ≥ your minimum). Random amounts weaken the exact-amount correlation an observer could otherwise use; an even split telegraphs the value.
- Shuffle order — recipients are sent to in random order, with a short random delay between each, so the batch is harder to reassemble by timing.
Every recipient must have opened Zolana once (same readiness check as a single send) — this is verified for all of them before any funds move. Each send is independent: if one fails mid-batch, the rest still go and the unsent funds simply stay in your private balance — press Split & send again to retry the remainder (you are never double-charged). The same honesty boundary applies: recipients and amounts are hidden per note, but the fact that your wallet made several private sends is public.
# Receiving privately
# Every wallet approval, explained
For trust, here is the complete list of popups Zolana can ever trigger. The in-app amber strip (FIG 2) announces each one before it appears. If your wallet shows a popup that doesn't match this list, reject it.
| When | Popup | What you are signing | Signature? |
|---|---|---|---|
| Connect (both sides) | Connect request | Nothing on-chain — just allows the app to see your address and request signatures later. | no tx |
| First use of a wallet | Privacy registration | One transaction creating your privacy account (encryption keys registered on-chain). Once per wallet, ever. | 1 signature |
| Send: funds preparation | Wrap SOL → wSOL | A standard token wrap of exactly the displayed amount into your own token account. Skipped when you already hold enough wSOL. | 1 signature |
| Send: shielding | Shield into private balance | The deposit moving the displayed amount from your public wSOL into the shielded pool. A ZK proof is generated locally first, so this popup can lag a few seconds behind the strip's announcement. | 1 signature |
| Send: the private send | Private send | The note creation that pays the recipient from your private balance. Recipient and amount are not visible on-chain. | 1 signature |
| Receive: claim | — none — | The claim is relayer-submitted precisely so you don't pay gas or leave a trail. The app says so in the strip. | no popup |
| Receive: wallet release / Recover pending | Withdraw to wallet | Moving the displayed amount from your private balance into your public wallet balance. | 1 signature |
# Reading the live operation trace
The Operation trace panel at the bottom of the app is open by default and logs every step with timestamps as it happens: funds checks, proof generation, transaction signatures, relayer submissions, MPC callbacks, and any errors verbatim. Three things to know:
- Blue lines are steps starting, green lines are confirmations (usually with a clickable explorer link), amber lines are wallet-approval announcements and warnings, red lines are errors.
- Every on-chain action logs its transaction signature — you can verify each one independently on Solana Explorer (devnet). Heads-up: opening a block explorer is a normal clearnet request from your browser to a third party — it ties your IP to that signature outside Zolana's mixnet. In strict mode, prefer copying the signature over clicking through if that matters to you.
- If you ever report a problem, a copy of this trace is the most useful thing you can attach.
# Fund recovery guide — nothing is lost mid-flow
A private transfer crosses several on-chain states. The key design fact: every intermediate state is durable and recoverable. Funds are only ever in one of four places — your public wallet, your private balance, a shielded note addressed to you, or a shielded note addressed to the recipient. Below is what to do for every interruption, in the order the states occur.
S1 · Send was interrupted after shielding (browser closed, error at the send step)
Where the funds are: your private balance (or a self-shield note about to become it). Nothing is in limbo on the network's side.
- Reopen the app, connect the same sender wallet, enter the same recipient/amount and click Send privately again.
- The app first checks your private balance — it finds the already-shielded funds, skips wrap/shield entirely, and goes straight to the private send. You will not be charged twice; pending self-shield notes are detected and claimed into your balance automatically.
S2 · Sent, but the recipient hasn't received anything yet
Where the funds are: a shielded note on-chain addressed to the recipient. It does not expire and cannot be taken by anyone else.
- The recipient simply connects their wallet in the Receive view — the inbox scan finds the note and schedules the claim automatically.
- If they were already connected, the inbox re-checks itself periodically; Receive privately forces a re-check immediately.
- Note the randomized claim delay shown on the item (e.g. claim in ~3 min) — that jitter is intentional; it weakens timing correlation between the send and the claim.
S3 · Claim failed or the browser closed while claiming
Where the funds are: still in the shielded note (a failed claim changes nothing on-chain) or already in the recipient's private balance if the claim landed.
- Zolana's receive queue is persisted locally (in your browser's IndexedDB). On reconnect, the scheduler resumes automatically: pending claims retry with backoff, and a note that turns out to be already claimed is detected and moves forward instead of erroring.
- Click Receive privately any time to force the queue to process now.
S4 · Claimed, but the funds aren't in the wallet yet
Where the funds are: the recipient's private balance, with a scheduled wallet release.
- The release time is shown on the item (e.g. available in ~5 min). When it fires you'll get one wallet popup to sign the withdrawal.
- Don't want to wait, or the release failed? Click Recover pending. It retries any recoverable queued withdrawals and sweeps your entire readable private balance to your wallet in one signed withdrawal. In strict-max this withdraws immediately, skipping the release jitter — a small timing-privacy trade-off for getting funds out now.
S5 · The browser/device was lost entirely
Where the funds are: on-chain — shielded notes and private balances belong to your wallet keys, not to the browser.
- On a new device, connect the same wallet. The inbox scan rediscovers claimable notes from the chain/indexer, and Recover pending sweeps any private balance. The local queue is only a scheduler — losing it loses no funds.
S6 · Strict mode says the mixnet is unavailable
Where the funds are: wherever they were — nothing moves over clearnet, by design (fail-closed).
- Wait and retry; mixnet gateways occasionally rotate. The action resumes exactly where the state machine left off (see S1–S4 — every state is durable).
- Zolana will never silently downgrade to a direct connection to "help". If you genuinely want a non-private test run, that's what the devnet-fast profile is — an explicit, labeled choice.
# Troubleshooting
| Message / symptom | What it means | What to do |
|---|---|---|
| "recipient is not ready to receive" | The recipient wallet has never connected to Zolana, so it has no privacy account. | Have the recipient open the app and click Connect recipient once (one-time registration). Then send again. |
| "not enough SOL to prepare wSOL" | The amount plus the fee buffer exceeds the sender's devnet SOL. | Get more devnet SOL from the faucet, or send a smaller amount. |
| "self-shield note was not indexed yet" | The protocol indexer is lagging behind the chain. | Wait ~1–2 minutes and click Send privately again — it resumes from the private-balance check (S1), nothing is lost. |
| "private balance is not ready yet" | The MPC callback that finalizes your balance hasn't landed yet. | Usually under a minute on devnet. Retry the send; it picks up where it left off. |
| "skipped stale/already-claimed note" | The protocol scanner re-returns spent notes; Zolana filters the ones it already settled. | Nothing — informational only. |
| "mixnet setup failed" / "mixnet unavailable" | Strict mode could not establish the Nym transport. | See S6. Wait/retry; nothing falls back silently. |
| Wallet popup is slow to appear | For shield/send, a zero-knowledge proof is computed in your browser first (seconds, device-dependent). | Watch the amber strip — it announces the popup before it arrives. Don't re-click; the button is disabled while a send runs. |
| No wallet detected | The browser has no Solana wallet extension. | Install Phantom or Solflare, then reload the page. |
# FAQ
Why is it slower than a normal Solana transfer?
Three honest reasons: ZK proofs are computed in your browser (seconds), the Arcium MPC network confirms private-balance operations asynchronously (tens of seconds), and in strict mode every network round-trip crosses three mixnet hops (~2.3s median vs ~0.4s direct, measured live). Zolana is built for transfers where privacy is worth seconds — and we position it exactly that way.
Why do claims and releases have random delays?
If a claim always followed its send by a fixed interval, an observer could link the two by timing alone. The jitter is part of the privacy, and you can always see the schedule on each item. Note the jitter is mode-dependent: strict-max spreads claims/releases over minutes; devnet-fast uses zero delay for fast testing (it is not network-private anyway). Also, the Recover pending button withdraws immediately and intentionally skips the release jitter — use it when you want funds now and the timing trade-off is acceptable.
What does Zolana store on my device?
Only the receive queue (note references, schedule times, signatures) in your browser's IndexedDB, keyed to your wallet address. No keys, no seed phrases, no balances. Losing it loses no funds (see S5). On a shared machine this is still a local linkage record, so the Receive view has a Clear local history button that wipes it on demand — your on-chain funds are unaffected and the inbox simply re-scans the chain next time you connect.
What does the relayer learn about me?
The relayer submits your claim, so it learns your wallet address as the claim recipient and when you claim (the claim transaction names your wallet publicly on-chain anyway). What it does not learn in strict mode is your IP — it sees a mixnet exit — and it cannot tell which deposit funded you, nor can it redirect funds: the ZK proof binds the claim to your registered keys.
What does my wallet extension see?
Your wallet (Phantom, Solflare, …) is outside Zolana's control and is its own trust boundary. It does its own clearnet RPC for connecting, showing balances, and simulating every transaction you sign — so the wallet vendor sees the transaction content and your IP regardless of Zolana's mixnet transport. This is inherent to browser wallets; we state it plainly rather than imply Zolana can mask it. Use a wallet you trust.
Is devnet-fast mode private?
The on-chain part, yes; the network part, no — and the app shows a permanent warning saying exactly that. Use strict-max for real network privacy.
What does it cost?
Phase A is fee-free (fee = 0) and has no token. You pay only Solana network fees on the transactions you sign.
# The privacy boundary, stated plainly
Zolana's claims are per-observer and bounded. Against a single passive observer (your RPC provider, your ISP, one network vantage point) the goal is to close the vector to near-chance, and that is what we test against devnet in CI. Against an active adversary running multiple mixnet hops, the cost is raised — not eliminated. A global passive observer watching all links at once is out of scope, and we say so.
What is always public, by protocol design: your wallet signs the pool deposit (so the chain — and Umbra's public indexer — records that your wallet used the pool), and the relayer-submitted claim transaction publicly names the recipient's wallet. What Zolana hides is who you paid, the amount, your network origin, and the link between a specific deposit and a specific claim. It does not hide the fact that you used the pool.
Anonymity-set context: the deposit→claim unlinkability is statistical — only as strong as the crowd of unspent notes in the pool. On devnet that crowd is minimal (a handful of test transfers), so an observer can often correlate a deposit and a claim by amount and timing; treat devnet as functional testing, not real privacy. On mainnet, Zolana rides Umbra's active pool, where the set is materially larger. The app surfaces this posture in the "Anon set" chip rather than hiding it, and never prints a fabricated number.
Finally, anything you do outside the app — pasting an address into a public explorer, or funding the recipient's wallet from the sender — is outside the boundary; the app warns where it matters.