Architecture
Contracts, circuits, indexer, and relayer in the Dome stack.
High-level flow
User wallet → deposit (proof + ETH) → EtherPool on Base
↓
Indexer scans events → wallet decrypts notes
↓
User wallet → withdraw proof → Relayer → EtherPool → recipientOn-chain
Deposits and withdrawals both call transact() on the pool. The contract verifies Groth16 proofs, updates the Merkle tree, and records nullifiers to prevent double-spends.
Notes are Poseidon-hashed and committed without revealing plaintext on-chain. Encrypted note payloads are emitted in events for clients that hold the viewing key.
Off-chain services
Indexer (@dome/backend)
- Scans
NewCommitmentlogs from the deployment block - Serves Merkle paths, encrypted outputs, and pool config
- Persists state in SQLite (local) or Postgres (testnet/production)
Relayer
- Accepts signed withdraw payloads from clients
- Pays gas and submits
transact()on behalf of users - Protected with
DOME_RELAYER_SECRETon public deployments
Circuits
| Primitive | Usage |
|---|---|
| Groth16 | Deposit and withdraw proofs |
| Poseidon | Note commitments and Merkle tree |
| 26 levels | Merkle depth (~67M leaves) |
Circuit artifacts are hosted for browser proving; SDK env DOME_CIRCUIT_KEY_BASE_PATH points at the WASM/zkey base URL.
Client stack
@dome/sdk-evm— Deposit, sync, withdraw in Node or bundlersdome-web/dome-mobile— Wallets using the SDK + hosted backend