Withdraw
How a withdrawal spends your notes and pays tokens out of a pool token account to a public Solana address, and what stays private when it does.
Umbra's clients, not the protocol
The platform wallet on this page is the wallet committed in slot 4 of your identity, which the protocol does use, for example in fee pricing. That Umbra's clients derive it from your account signature is their standard, not a protocol rule.
A withdrawal spends notes you own and pays tokens out of the pool token account to a public Solana address. The destination, the token and the amount are public, because tokens cross out of the pool there. Which notes paid for it, and whose they were, stay private.
Summary
A withdrawal is the shielded pool's process_3x3x2x2 transaction with a withdrawal lane active, which pays a public amount of one token from that token's pool token account to a destination named in the transaction. The transaction has two withdrawal lanes, and the SDK uses one. It spends up to three of your notes and usually creates one new note: your change.
Each withdrawal lane has a public counterparty, which the proof binds. For an SPL Token or Token-2022 token the destination is a token account of that mint and the counterparty is its owner. For SOL the destination is the wallet itself, paid plain SOL from the pool's lamport account.
The screener screens the submitter and each lane's counterparty, and signs only a Clear verdict. A relayer submits and adds the nullifier freshness proof, as for a private transfer.
A withdrawal needs no allowlist entry: when governance revokes a token, new deposits of it stop, but transfers and withdrawals continue.
Before you start
- You are registered and hold enough. The proof shows your identity commitment is in the identity tree, and your notes of the token must cover the amount, the protocol fee on the withdrawal and on any change note, and the relayer's tip.
- The destination can receive it. A token destination must be a token account of the same mint; if it does not exist yet, the relayer can create the owner's associated token account for a published extra fee. A SOL payment to a wallet that does not exist yet must be at least the rent-exempt minimum.
- The pool can fund it. One pool token account per token, shared by every pool index, must hold the amount. For SOL, the pool's lamport account must hold it above the minimum balance it always keeps.
- A relayer will carry it, and every attester is available. As for a private transfer.
How a withdrawal runs
A withdrawal runs in the same three phases as a private transfer. Your device prepares the transaction, collects the six attester signatures while it proves, and hands the instruction to a relayer, which adds the freshness proof and submits.
flowchart LR A["Your device prepares"] --> B["Attesters sign"] A --> C["Your device proves"] B --> D["Relayer submits"] C --> D D --> E["Pool verifies"] E --> F["Pool pays out"]
A withdrawal adds a public destination, which the screener also screens, and a payout at the very end.
Phase 1: preparing on your device
Your device prepares the transaction itself, with one read each from the relayer and the indexer.
sequenceDiagram participant U as Your device participant R as Relayer participant I as Indexer participant Z as Zone authority U->>R: read policy R-->>U: submitter, tip accounts U->>I: one read for paths I-->>U: paths and fee rates U->>U: build change note and lane opt notes outside zone 0 U->>Z: authorisation message Z-->>U: EdDSA signature end
1. Your device reads the relayer's policy and selects notes
The SDK reads the relayer's policy first, because the relayer's tip account is part of what every attester signs. It checks that the relayer carries this token and accepts the tip, adds the creation fee if the destination does not exist yet, and chooses up to three of your notes of the token.
2. The indexer returns paths and fee rates
One request to the indexer returns the Merkle paths for your notes, your identity tree path and the fee rates. The paths must match roots the pool still accepts, or the proof fails.
3. Your device builds the change note and the lane
The SDK prices the protocol fees, then builds the withdrawal lane (token, amount and destination) and your change note, which it encrypts to you. It builds the sender record and splits the per-transaction viewing key into three shares, one per guardian node. The destination is part of the context digest every attester signs, and the proof binds the counterparty, so nobody downstream can redirect the payout.
4. The zone authority signs, outside zone 0
If the notes you spend, or your change note's zone, are outside zone 0, a signer from that zone's authority signs a message derived from the context digest. The proof checks these signatures, and they never appear on chain. See zones.
Phase 2: collecting signatures and proving
The screener checks the submitter and the public counterparty of each withdrawal lane, while the other attesters sign and your device proves.
sequenceDiagram participant U as Your device participant G as Guardian nodes participant S as Screener participant A as Other attesters Note over A: fee enclave, data endorser par attest U->>G: one encrypted share each G-->>U: three BLS signatures U->>S: payload and accounts S-->>U: BLS signature if Clear U->>A: openings, change note A-->>U: two BLS signatures and prove U->>U: transaction proof end
5. Each guardian node checks its share and signs
Each node decrypts its share of the per-transaction viewing key, checks it against its commitment, escrows it and signs the context digest. It does not check the proof or any amount. See what a guardian node checks.
6. The screener screens the submitter and destination party
The screener works out the submitter and the destination party: the owner of the destination token account, or the wallet itself for SOL. If any screening answer is missing the verdict is Indeterminate, even if another flagged a wallet; otherwise any flag makes it Deny. Only Clear produces a signature, so without it the withdrawal cannot land. See screening.
7. The fee enclave opens the fee commitments and signs
The fee enclave opens the three fee commitments, applies any discount from its schedule, and refuses a withdrawal lane whose token is not one of the transaction's three fee slots. It escrows the openings and signs.
8. The data endorser checks the change note and signs
The data endorser checks that the encrypted change note matches the memo digest in the payload, archives it and signs. Your device later finds the change note in that archive.
9. Your device proves and hands the instruction to the relayer
Your device makes the transaction proof and combines the six BLS signatures into one combined attester signature. It sends the relayer the finished instruction, leaving the nullifier root and freshness proof for the relayer to fill.
Phase 3: relaying, verifying and paying out
The relayer submits, and the pool pays out only once it has verified everything.
sequenceDiagram participant R as Relayer participant P as Shielded pool participant T as Pool token account participant X as Destination R->>R: validate, prove freshness R->>P: signed v1 transaction P->>P: checks, both proofs P->>T: pay the lane T->>X: tokens P->>P: credit relayer tip
10. The relayer validates, creates the destination if asked, and submits
The relayer checks the request against its policy and the chain, including that an existing token destination holds the lane's token. It creates a missing destination only if it is the named owner's associated token account and the tip covers its published creation fee; a relayer with no such fee creates none. It then proves nullifier freshness against the latest nullifier root and sends a Solana v1 transaction as submitter and fee payer, with any destination created ahead of the withdrawal.
11. The shielded pool checks and verifies
The program runs the ordered checks of any value transaction, listed on the deposit page. Before it verifies the combined attester signature or either proof, it refuses the transaction if the pool cannot fund the withdrawal lanes. The proof's public input includes each lane's token, amount and counterparty, which the program reads from the destination account itself, so a proof made for one destination cannot pay another.
12. The shielded pool records the spend and pays out
The program stages the three nullifiers and three fee commitments and appends three note commitments to the note tree. It then pays each lane: a token by a checked transfer signed by the pool token authority, a program-derived address only the program's own logic can make sign, and SOL in lamports from the pool's lamport account straight to the wallet, with no signature at all. Finally it credits the relayer's tip to its tip accrual for that token. See SOL.
What a chain observer sees
- Program
- Shielded pool, process_3x3x2x2
- Submitter and fee payer
- The relayer's own address
- Destination
- The token account or wallet paid
- Token
- The mint paid out
- Amount
- The amount paid out
- Relayer tip
- An amount and a token, or nothing
- Nullifiers
- Three field elements
- New note commitments
- Three field elements
- Fee commitments
- Three field elements
- Who withdrew
- Private
- Which notes paid for it
- Private
- Change left behind
- PrivateInside a note commitment
- Protocol fee
- PrivateInside the fee commitments
- Zone
- Private
What can go wrong
- The screener does not clear the submitter or the destination. No signature is produced, nothing moves and your notes are untouched.
- The destination is not usable. A token account of another mint, a missing account the relayer was not paid to create, or a SOL payment below the rent-exempt minimum to a wallet that holds no lamports is refused.
- The pool cannot fund it. The program refuses before it verifies the signature or the proofs.
- A root or the proof is too old, a nullifier is already staged, or an attester is down. These fail as they do for a private transfer, and the escape hatch is the way out when an attester will not sign.
Privacy notes
- The lane is public. Anyone can see where the tokens went, which token and how much.
- Amounts and timing correlate. A withdrawal of about a deposit's amount, soon after it, is easy to link; waiting and choosing amounts that do not echo a deposit weakens that. See how privacy is lost.
- Destinations can identify you. Withdrawing to your main or platform wallet links the withdrawal to your public registration, and reusing a destination links your withdrawals to each other.
- Your platform wallet counts as you for fees. A withdrawal to it is priced as same-owner and one to your main wallet is not, because only the platform wallet is committed inside your identity. See the fee model.
- The tip's token is public. By default it is the token withdrawn, which is public here anyway.
Related
Escape hatch
Withdrawing one note when the attesters cannot or will not sign.
Screening
What the screener checks on every withdrawal lane.
Pool token accounts and tokens
How pooled tokens are held and what revoking a token does.
How privacy is lost
Deposit and withdrawal correlation, and reused destinations.
Last updated
Private transfer (Private Send)
How a private transfer spends your notes and creates new ones for a recipient, what the relayer adds, and what each party can and cannot learn.
Receive and sync
How an encrypted note reaches its recipient, how your device finds your notes among everyone's, and how it works out your balance and history.