Withdrawal
Privacy Pools supports two types of withdrawals:
- Direct Withdrawals: User directly interacts with pool contract
- 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
Aspect | Direct Withdrawal | Relayed Withdrawal |
---|---|---|
Privacy Level | Basic | Enhanced (different withdrawal address) |
Gas Payment | User pays directly | Relayer pays, takes fee |
Fee Structure | No fees | Configurable relayer fee |
Complexity | Simpler flow | Additional fee computation |
Front-running Protection | Context-based | Context-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
- Proof Generation
- User constructs withdrawal parameters
- Generates ZK proof of commitment ownership
- Computes new commitment for remaining value
- Contract Interaction
- User submits proof to pool contract
- Pool verifies proof and context
- Updates state (nullifiers, commitments)
- Transfers assets to recipient
Relayed Withdrawal
- User Steps
- Construct withdrawal with Entrypoint as processooor
- Generate ZK proof
- Submit to relayer off-chain
- Relayer Steps
- Verify proof locally
- Submit transaction to Entrypoint
- Pay gas fees
- 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;