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).
See Contract Architecture.

Verifiers

Three UltraHonk verifiers, one per circuit. Each exposes verify(bytes proof, bytes32[] publicInputs).

RPC proxy

The Veilify Network endpoint. It owns note scanning, balance computation, note selection, fee quoting and the veilify_* 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 call approveDeposit, 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 calls canUpgrade(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.