This chapter is the map for engineers: the contract families ZKDepth deploys, the programs around them, and the two paths data takes.
The map
The browser, the API and its bots, the indexer, the signer, the relayer and the sealed batch keepers sit off chain, and all of them reach the contracts through the Robinhood Chain RPC. Addresses are in Contracts.
Contract families
| Family | What it holds | Chapter |
|---|---|---|
| Position tools | ZKDepthZapV3, ZKDepthZapV4, RangeOrders, PositionKeeper | Zap, Limit orders, Keeper |
| Vaults | VaultFactory, LPVault, HedgedLPVault, StructuredVault | Vaults, Hedged, Notes |
| Graduation | LaunchPipeline, PreMarketPerp | Token vaults |
| Public venue | ProtocolConfig, AssetRegistry, DammHook, StockHook, DLMM, Router, pool vaults, LaunchPools | Pools, Swaps, Launch pools |
| Fees | FeeRouter, ReferralRegistry, fee collectors, BuybackV2 | Fees, Buyback |
| Perps engine | PerpEngine, PerpVault, FundingModule, InsuranceFund, PerpOracle, PerpMarketRegistry | Perps |
| Launchpad | LaunchFactory, BondingCurve, GraduationManager, LPAllocationEscrow, LaunchConfigRegistry | Launch |
| Shielded core | ShieldedPool, AssetCustody, TransactionVerifier, SwapAdapter, DlmmAdapter, VaultAdapter, LaunchAdapter, PerpAdapter, EthExitAdapter | Private balance, Immediate lane, Private perps |
| Sealed batches | SealedBatches, SealedMarkets, a SealedLaunchOpener per launch that uses one, the order, claim and refund verifiers | Sealed batches |
The families meet at fees: FeeRouter's treasury is the venue's FeeCollector, so whatever referrers do not earn joins the pools' protocol fees on the way to the $ZKD buyback. Who can call what is in Who can do what.
The programs off chain
| Program | Code | Job | Holds |
|---|---|---|---|
| Web app | apps/web | every page and every user transaction | nothing, your wallet signs |
| API | apps/api | the routes pages read, the perp proxy, ideas and points | the signer's shared secret |
| Bots | apps/api/src/bots | upkeep transactions | one hot bot key |
| Indexer | apps/indexer | logs into tables, served to the API alone | nothing |
| Signer | services/signer | Lighter onboarding and order signing | Lighter order keys, encrypted |
| Relayer | apps/relayer | submits private proofs for a quoted fee | a gas key |
| Sealed batch keepers | apps/keeper, three of them | read order logs, post share sums, try a post again if it could not settle, void stale tranches | a gas key and a share secret each |
Indexer, API and bots covers the first four, Perps on Lighter the signer and Sealed batches the keepers.
The relayer's URL is the only private-lane server the browser talks to. The browser reads pool and sealed lane logs through a same-origin RPC route whose keys stay on the server, and builds Merkle paths itself. The API's GET /shielded/stats answers aggregates only: set size, total per asset and action counts. No route takes a commitment or an address.
A write, from click to block
Every button that changes chain state calls useWrite().run(...) in apps/web/lib/tx.ts.
- 1GateThe hook checks for a connected wallet, chain 4663 and a deployment manifest.
- 2SimulateAn
eth_callfrom your address. A revert stops here, and your wallet never opens. - 3Sign and sendYour wallet signs the simulated request and sends it through the RPC.
- 4RefreshThe queries the write affects are refetched as the indexer sees the new logs.
A deposit into the private balance is the one exception: the @zkdepth/zk client sends it to your wallet with no simulation first.
For anything a transaction must get exactly right, the browser reads the chain directly. A private action loads the proving key for its circuit, proves in a browser worker, and a relayer or a fresh address submits it. The API's POST routes store a signed idea, forward a signed perp request to the signer, or return a plan for your wallet to send.
A read, from chain to page
A page hook in apps/web/lib/data.ts calls a typed fetcher in apps/web/lib/api.ts. The API answers from the indexer, from chain reads batched through Multicall3, from market data or from its database, and a cached route keeps its answer for 15 to 60 s. It maps its own model to the exact shape api.ts declares, and a test fails if either side renames a field. The indexer is fed by the chain alone.
Shared packages
@zkdepth/coreis pure TypeScript: tick and zap maths, fee APR, hedge sizing, note payoffs, DLMM bin maths, slippage. A number on a card and the number a bot acts on come from the same function.@zkdepth/abiholds the compiler ABIs, the chain's fixed addresses and the manifest type. The manifest is the one file that says where a deployment lives.@zkdepth/agentholds the routes, plans and tools agents and the app share.@zkdepth/zkholds keys, notes, the tree, proving workers, scanning and every private action.
Deploying the stack
DeployRobinhood.s.sol and DeployLocal.s.sol both call deployAll, which deploys the venue, the fee contracts, the position tools, the vaults, the perps engine and the launchpad, creates the seed vaults, then proposes the owner for the admin contracts. Until the owner calls acceptOwnership, the deployer still holds them. The deploy then adds the private balance, its adapters and the sealed lane, on the verifiers it is given, and names the lane's opener list to the launchpad. The owner adds sealed markets after, with the operators' keeper keys. scripts/dev-local.sh runs the same deploy on a local fork, on development proving keys.
contracts/script/ZKDepthWiring.soldeployAll, the seed vaults and writeManifestapps/web/lib/tx.tsuseWrite, the one write pathpackages/abi/src/manifest.tsthe manifest type and loadManifest