V5 Proxy Withdrawals
Overview
V5 introduces proxy-based withdrawal patterns for enhanced privacy and gas efficiency.
Key Concepts
Proxy Pattern
- Users deposit into a proxy contract first
- Proxy handles Merkle tree updates and proof generation
- Reduces on-chain footprint of withdrawal operations
- Enables batching multiple withdrawals in single transaction
Contract Addresses (Paseo AssetHub)
| Contract | Address | Purpose |
|---|---|---|
| Shield | 0x327773DAF3E145623b9CF5E78c8Cbc09c657e14b | Main shield contract |
| Verifier | 0x471Aea61fA91cb122f1A00Da5f476eB69dc114Ed | ZK proof verification |
| LeanIMT128 | 0xFF8Ead5c88CdEf89f9E5514F00e1D9db09ac5Ca5 | Merkle tree storage |
| PoseidonT3 | 0x1d165f6fE5A30422E0E2140e91C8A9B800380637 | Hash function |
Withdrawal Flow
- Build Merkle Tree: Reconstruct from contract events starting from
deploymentBlock: 9592061 - Generate Proof: Use
withdraw_phase2_fixedcircuit with 7 public signals - Validate Root: Compare local
tree.rootwithcontract.currentRoot() - Execute Withdrawal: Call
withdrawNative()orwithdraw()with proof
7 Public Signals
V5 contract requires uint[7] calldata pubSignals:
pubSignals = [root, nullifierHash, existingValue, newValue,
existingSecret, newSecret, assetId]
Use padTo7Signals: true when calling zkWithdraw() for native tokens (assetId = 0).
Event Signatures
Deposit(address,bytes32,uint256) // token, commitment, amount
Withdrawal(address,uint256,address,uint256) // caller, amount, recipient, nullifierHash
NewCommitment(bytes32) // commitment
Known Limitations
- Proxy contract
0x94196fF8Fb407F84414dfd6749d88D3FBc1dd1F6has 85 leaves without historical events - Use main contract for full tree reconstruction
- Addresses must be lowercase to avoid EIP-55 checksum validation errors
Troubleshooting
- Duplicate commitments: Track with
Set<string>to prevent double insertion - Wrong tree depth: Local tree must match contract's expected
treeDepth: 128 - Event scanning slow: Use
deploymentBlockto skip historical blocks