Skip to main content

Withdrawal

Privacy Pools supports two types of withdrawals:

  1. Direct Withdrawals: User directly interacts with pool contract
  2. Relayed Withdrawals: Withdrawal processed through a relayer for additional privacy

Both methods require zero-knowledge proofs to prove commitment ownership and maintain privacy.

Withdrawal Types Comparison​

AspectDirect WithdrawalRelayed Withdrawal
Privacy LevelBasicEnhanced (different withdrawal address)
Gas PaymentUser pays directlyRelayer pays, takes fee
Fee StructureNo feesConfigurable relayer fee
ComplexitySimpler flowAdditional fee computation
Front-running ProtectionContext-basedContext-based

Protocol Flow - Direct Withdrawal​

Protocol Flow - Relayed Withdrawal​

Withdrawal Data Structure​

struct Withdrawal {
address processooor; // Direct: recipient, Relayed: Entrypoint
uint256 scope; // Pool identifier
bytes data; // Direct: empty, Relayed: encoded `FeeData`
}

struct FeeData {
address recipient; // Final recipient
address feeRecipient; // Relayer address
uint256 relayFeeBPS; // Fee in basis points
}

Withdrawal Steps​

Direct Withdrawal​

  1. Proof Generation
    • User constructs withdrawal parameters
    • Generates ZK proof of commitment ownership
    • Computes new commitment for remaining value
  2. Contract Interaction
    • User submits proof to pool contract
    • Pool verifies proof and context
    • Updates state (nullifiers, commitments)
    • Transfers assets to recipient

Relayed Withdrawal​

  1. User Steps
    • Construct withdrawal with Entrypoint as processooor
    • Generate ZK proof
    • Submit to relayer off-chain
  2. Relayer Steps
    • Verify proof locally
    • Submit transaction to Entrypoint
    • Pay gas fees
  3. Entrypoint Processing
    • Verify proof and context
    • Process withdrawal through pool
    • Handle fee distribution
    • Transfer assets to recipient

Context Generation​

The context signal binds the proof to specific withdrawal parameters:

context = uint256(keccak256(abi.encode(
withdrawal,
pool.SCOPE()
))) % SNARK_SCALAR_FIELD;