Privacy Wallet · Technical Docs

Transaction flow

Withdrawal: Prepare phase

Generating ZK proofs off-chain and submitting them to create a prepared transaction.

Off-chain proof construction

1. Note selection

The client chooses input notes whose total value covers the intended withdrawal and fees.

2. Merkle proofs

For each note, the client obtains a Merkle path proving inclusion under a specific root.

3. Nullifiers

The client computes one nullifier per input using:

VoidHash(receiverViewPriv, spendNonce)

4. Change outputs

Any excess value is allocated to new output notes with new commitments.

5. Groth16 proof

A witness is built and a Groth16 proof is generated that all circuit constraints hold.

On-chain validation

  • Proof verification. The program verifies the Groth16 proof and checks the layout of public inputs.
  • Nullifier checks. Every input nullifier is checked against NullifierFlag PDAs; reuse is rejected.
  • Amount validation. The equality is enforced: Σ inputs + extAmountIn = Σ outputs + publicAmount.
  • Solvency check. The pool must hold at least publicAmount lamports.
  • Fee calculation. A relayer fee of 0.15% plus a fixed gas buffer is computed.

State changes

  • Nullifier flags. One NullifierFlag PDA is created per consumed note.
  • Tree updates. Output commitments are appended to the tree, changing the root.
  • Prepared transaction. A PreparedTx PDA is created, capturing recipient, public amount, fee, and expiry.