Privacy & Confidential Transfers
Shielded Transfers
End-to-end guide to shielding, transferring, and unshielding ETH and ERC-20 tokens using the ConfidentialLedger.
Overview
Shielded transfers let entities move ETH and ERC-20 tokens privately on-chain. The system uses a UTXO-based note model with Poseidon commitments and Halo2-KZG zero-knowledge proofs on BN254.
Three operations are supported:
| Operation | Description |
|---|---|
| Shield | Deposit public tokens into the private ledger, creating a shielded note |
| Transfer | Send shielded tokens to another entity without revealing amounts or identities on-chain |
| Unshield | Withdraw shielded tokens back to a public address |
How It Works
Shield (Deposit)
- Entity calls
POST /api/privacy/shieldwith token, amount, and chain - The API derives the entity's key set, computes a Poseidon commitment, and encrypts the note data
- A UserOp is submitted through the entity's smart wallet to
ShieldedTransferFacet - The facet calls
ConfidentialLedger.shield(), which inserts the commitment into the Merkle tree - The scanner detects the
NoteCreatedevent, trial-decrypts it, and records the note in the database
Private Transfer
- Entity calls
POST /api/privacy/prove-transferwith recipient, token, and amount - The API selects input notes (coin selection), fetches Merkle paths from on-chain
- A JoinSplit proof is generated via the native Halo2-KZG prover (2 inputs, 2 outputs)
- The proof bundle is returned to the client, which submits it to
POST /api/relay/transfer - The relay submits the transfer anonymously — the sender's wallet never appears on-chain
- The ConfidentialLedger verifies the proof, records nullifiers, and inserts new commitments
Unshield (Withdrawal)
- Entity calls
POST /api/privacy/unshieldwith token, amount, and optional recipient - The API selects input notes, generates a proof with
value_deltaequal to the withdrawal amount - A UserOp is submitted to
ShieldedTransferFacet.unshieldTokens() - The facet calls
ConfidentialLedger.unshield(), which verifies the proof and sends tokens to the recipient
Token Support
| Chain | Token | Address | Status |
|---|---|---|---|
| Base Sepolia | ETH | address(0) | Supported |
| Base Sepolia | USDC | 0x036CbD53842c5426634e7929541eC2318f3dCF7e | Supported |
| Base | ETH | address(0) | Supported |
| Base | USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | Supported |
| Base | DAI | 0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb | Supported |
Native ETH uses the address(0) sentinel in the ConfidentialLedger. The contract wraps/unwraps ETH automatically.
Gas Estimates
| Operation | Gas | Approx. Cost (Base) |
|---|---|---|
| Shield (ETH) | ~80,000 | ~$0.01 |
| Shield (ERC-20) | ~120,000 | ~$0.01 |
| Private Transfer | ~350,000 | ~$0.03 |
| Unshield | ~350,000 | ~$0.03 |
All operations are sponsored by the platform paymaster — entities do not need to hold ETH for gas.
Accounting Integration
Shielded transfers are automatically classified and posted through the posting engine:
| Event Type | Debit | Credit |
|---|---|---|
shielded_deposit | assets.crypto.shielded | cash.usdc |
shielded_withdrawal | cash.usdc | assets.crypto.shielded |
shielded_transfer_in | assets.crypto.shielded | assets.crypto.shielded |
shielded_transfer_out | assets.crypto.shielded | assets.crypto.shielded |