Privacy Wallet · Technical Docs

Transaction flow

Deposit transaction

Moving public SOL into the Void privacy pool and minting a shielded note commitment.

Summary

A deposit transfers SOL from a standard wallet into the privacy pool, generating a new note commitment in the global Merkle tree. The user receives an encrypted note they can later spend privately.

Conceptual flow

Step 1: User prepares deposit
---------------------------------
[ User Wallet ]
    |
    |  choose amount
    |  derive noteNonce
    v
[ Client ]
    |
    |  commitment = VoidHash(amount, noteNonce)
    |  ciphertext = Encrypt(note, receiverViewKey)
    v
[ deposit_with_note() transaction ]

Step 2: Program processes deposit
---------------------------------
[ Void Program ]
    |
    |  verify lamports in Pool PDA
    |  append commitment to Merkle tree
    |  update global root + history
    |  create NoteRecord PDA(commitment, ciphertext, metadata)
    v
[ Updated GlobalState + NoteRecord ]

Process steps

1. User action

The wallet invokes deposit_with_note, attaching a lamport transfer to the pool PDA and including encrypted note data.

2. Commitment generation

Off-chain, the client computes the commitment for the new note:

commitment = VoidHash(amount, noteNonce)

3. Encryption

Note details (amount, nonces, keys) are encrypted for the recipient view key and attached as ciphertext.

4. Tree insertion

The program appends the commitment to the Merkle tree, updates the root, and pushes it into the root history ring buffer.

5. Note storage

A NoteRecord PDA keyed by the commitment is created and stores ciphertext plus minimal metadata.

Resulting state

  • Pool PDA. Holds the deposited lamports controlled solely by the program.
  • Merkle tree. Contains a new leaf for the note, reflected in the global root.
  • NoteRecord PDA. Carries encrypted note data for later discovery by the recipient.