Pool contract
The single source of truth. It holds two append-only Merkle trees, the nullifier sets and every pooled token.- Note tree: LeanIMT of note commitments, max depth 32. Every historical root stays valid.
- Key registry tree: LeanIMT of inbox-key hashes. One leaf per address, forever.
- Note nullifiers:
mapping(uint256 => bool). A spent note can never be spent again. - Transaction nullifiers:
mapping(bytes32 => bool). A signed transaction can only execute once. - Pending deposits:
index → keccak256(recipient, token, amount, depositor, gasEscrow).
Verifiers
Three UltraHonk verifiers, one per circuit. Each exposesverify(bytes proof, bytes32[] publicInputs).
RPC proxy
The Veilify Network endpoint. It owns note scanning, balance computation, note selection, fee quoting and theveilify_* API. It talks to the prover and relayer.
Prover
Builds the witness from the signed transaction, the selected notes and their Merkle paths. It produces an UltraHonk proof over BN254. The prover is the only component that needs the full private witness.Withdrawal scheduler
Owns the Round-mode lifecycle. It stores prepared intents and signed jobs, reserves notes and nonces, and proves each job before its round. At the round it dispatches through the relayer.Relayer
An allowlisted address (allowedRelayers). Any private operation with fee > 0 must come from a relayer. The relayer pays gas and receives fee in feeTokenAddress. A fee-less operation can be submitted by anyone.
Gatekeeper
A privileged address that screens deposits. It is the only address that can callapproveDeposit, rejectDeposit and pullDeposit. It is reimbursed for gas from each deposit’s escrow, never beyond it. See Gatekeeper.
Upgrade controller
The contract that holds admin power. The pool callscanUpgrade(msg.sender, …) to authorize upgrades and every admin setter. AdminUpgradeController is a single-admin controller that can be swapped for a timelock or multisig with setUpgradeController.