ShieldedPool Contract
The core contract managing the shielded pool for a single ERC20 token.
Overview
Each ShieldedPool instance wraps one ERC20 token. It maintains:
- An incremental Merkle tree (depth 20, Poseidon hashing) of note commitments
- A nullifier registry for double-spend prevention
- Historical root storage (last 100 roots) for proof freshness tolerance
Functions
deposit
function deposit(uint256 amount, uint256 commitment) external
Locks ERC20 tokens in the pool and inserts a note commitment into the Merkle tree.
| Parameter | Description |
|---|---|
amount | Token amount in whole units (contract scales by amountScale) |
commitment | The note commitment (Poseidon hash) |
Events: Deposit(commitment, leafIndex, timestamp)
info
Deposit amount is visible on-chain (the ERC20 transferFrom is public). Privacy begins after deposit.
transfer
Executes a private transfer inside the pool. Consumes one note (via nullifier) and creates two new notes.
The contract:
- Checks
merkleRootis in the known roots set - Checks
nullifierHashhasn't been spent - Verifies the Groth16 proof against 4 public inputs
- Marks nullifier as spent
- Inserts both new commitments into the Merkle tree
- Emits
PrivateTransferevent with encrypted memos
withdraw
Exits the shielded pool. Consumes a note and releases ERC20 tokens to the recipient.
| Parameter | Description |
|---|---|
proof | Groth16 proof bytes |
amount | Withdrawal amount (public, needed to release ERC20) |
changeCommitment | Change note commitment (0 if full withdrawal) |
recipient | Address to receive the ERC20 tokens |
Merkle tree
- Type: Incremental append-only
- Hash: Poseidon (t=3, 2 inputs)
- Depth: 20 (supports 1,048,576 commitments)
- Zero values:
zero[0] = 0,zero[i] = Poseidon(zero[i-1], zero[i-1]) - Root history: Circular buffer of last 100 roots
- Leaves are never removed — a "spent" note still exists in the tree, its nullifier just prevents reuse
Gas costs
| Operation | Estimated Gas |
|---|---|
| Deposit | ~300,000 - 400,000 |
| Transfer | ~450,000 - 550,000 |
| Withdraw | ~350,000 - 450,000 |