This chapter is the map for engineers: every contract Levee deploys, the programs that run around them, and the two paths data takes, a write from your wallet to a contract and a read from the chain back to a page. Every other chapter zooms into one part of it. Every name in code can be found with a search of the repository.
The map
Read it from the top. The browser, the API and its bots, the indexer and the signer sit off chain, and all of them reach the contracts through the Robinhood Chain RPC. On chain, the contracts fall into two families with separate histories. The liquidity-management contracts in contracts/src work on top of Uniswap v3 and v4. The venue in contracts/src/venue is Levee's own set of pools, router and fee path. They meet at one point: FeeRouter collects the fees of the first family and names the venue's FeeCollector as its treasury, so whatever referrers do not earn joins the pools' protocol fees on the way to the $LEVEE buyback.
Nothing in contracts/src is behind a proxy, and nothing can be upgraded. The liquidity-management contracts have no owner and no admin function. In the venue, ProtocolConfig, AssetRegistry, FeeCollector and BuybackV2 are Ownable2Step. Their owner can tune parameters, steer fees and pause swaps and new liquidity. Withdrawals never check the pause. Security model lists every power that key has.
Contracts by job
Each table names who creates the contract, what it is for and what it calls. "deployAll" means the contract is deployed once by LeveeWiring.deployAll. "deployVenue" means the venue half of that same call.
Position tools
| Contract | Created by | What it does | Calls |
|---|---|---|---|
LeveeZapV3 | deployAll | Takes one token, skims 25 bps, swaps the excess side, then mints or tops up a v3 position. Holds nothing between calls. | NPM, SwapRouter02, FeeRouter |
LeveeZapV4 | deployAll | The same over the v4 PoolManager, hooks included. | PoolManager, v4 PositionManager, Permit2, FeeRouter |
RangeOrders | deployAll | Holds a one-sided v3 position as a limit order that earns fees until the price crosses it. Anyone may fill; only the owner may cancel. | NPM, FeeRouter |
PositionKeeper | deployAll | Lets anyone harvest or rebalance an enrolled v3 position under the owner's policy, for a bounty of at most 300 bps. | NPM, SwapRouter02, FeeRouter |
Details: One-token deposits, Limit orders, Position automation.
Vaults
| Contract | Created by | What it does | Calls |
|---|---|---|---|
VaultFactory | deployAll | Clones the three vault implementations (EIP-1167) and initialises each clone in the same transaction. Anyone may create a vault, so the factory's list is not a recommendation. | the implementations |
LPVault | VaultFactory | ERC-4626 shares over one v3 range, priced behind a TWAP guard, harvested and rebalanced by anyone. | NPM, SwapRouter02, FeeRouter |
HedgedLPVault | VaultFactory | An LPVault whose price exposure is shorted on Lighter, in its funder's Lighter account. The hedger reports the short; the funder moves margin. | Lighter deposit (through HedgeFunding), Chainlink ETH/USD |
StructuredVault | VaultFactory | A dated note: an LPVault sleeve plus an off-chain long (Income) or SGOV (Protected), unwound at maturity. Leaving early costs 50 bps. | its LPVault, SGOV pool, Chainlink, FeeRouter |
Details: Vaults, Hedged vaults, Structured notes.
Launch tracking and pre-market perps
| Contract | Created by | What it does | Calls |
|---|---|---|---|
LaunchPipeline | deployAll | track records when a token's WETH pool was first seen. graduate clones an LPVault over it once the token is 3 days old and its pools hold MIN_LIQUIDITY. | v3 factory, VaultFactory |
PreMarketPerp | deployAll | A virtual-AMM perp for tokens no venue lists: USDG margin, 3x, an index price from a 30 min v3 TWAP times Chainlink ETH/USD. Anyone may open a market. | v3 pools, Chainlink, FeeRouter |
Details: Graduation and pre-market perps.
Levee pools and routing
| Contract | Created by | What it does | Calls |
|---|---|---|---|
ProtocolConfig | deployVenue | The venue's switches: pause, the protocol share of every pool fee (2 000 bps at deploy, at most 5 000) and the FeeCollector address. | none |
AssetRegistry | deployVenue | The curated list of oracle-priced assets and the quotes they may pair with. USDG is $1; ETH and WETH use Chainlink ETH/USD. | Chainlink |
DammHook | deployVenue, at a mined CREATE2 address | Permissionless dynamic-fee v4 pools: a 5 to 100 bps base fee, an optional anti-snipe start fee and a volatility surcharge, capped at 500 bps outside the snipe window. | PoolManager, ProtocolConfig |
StockHook | deployVenue, at a mined CREATE2 address | v4 pools for registry assets. The fee follows the market session, and a swap must end inside the oracle band or move the price toward it. | PoolManager, AssetRegistry, ProtocolConfig |
DlmmFactory, DlmmPair | deployVenue; pairs by anyone | Discrete-bin pools with a fixed price per bin, one pair per token pair and bin step. | ProtocolConfig |
DlmmPositionNFT | deployVenue | ERC-721 positions over a contiguous range of bins. | DlmmPair |
DlmmLimitOrders | deployVenue | Limit orders as single-bin liquidity, batched per bin. Anyone may execute a filled batch. | DlmmPair |
Router | deployVenue | Exact-in, multi-hop swaps across v4 pools (Levee hooks, Pons graduated pools and others), DLMM pairs and Pons bonding curves (through the PonsAdapter library). Holds nothing and charges nothing. | PoolManager, DlmmPair, Pons |
Both hooks and every DLMM pair send the protocol share of each fee straight to FeeCollector. Details: Levee pools, Swaps and routing.
Pool vaults and launches
| Contract | Created by | What it does | Calls |
|---|---|---|---|
DlmmVaultFactory, DlmmVault | deployVenue; vaults by the owner | ERC-20 shares over the bins around the active one. Only the factory's keeper (or the owner) rebalances, at most every 5 min. | DlmmPair |
DlmmVaultZap | deployVenue | One-token deposits into, and withdrawals out of, a DLMM vault. | Router |
StockVaultFactory, StockVault | deployVenue; vaults by the owner | Passive liquidity in one stock pool, centred on the oracle price and wider while the market is closed. | PoolManager, StockHook |
LaunchPools, LaunchToken | deployVenue; tokens by launch | A fixed-supply token and its locked native-ETH DAMM pool in one transaction, with an optional first buy. | PoolManager, DammHook |
LaunchVault | deployVenue | Pools ETH before a launch, buys the token as the pool's first swap and shares it pro rata. | LaunchPools |
Details: Levee pools, Launch a token.
Fees and $LEVEE
| Contract | Created by | What it does | Calls |
|---|---|---|---|
FeeRouter | deployAll | The sink for every protocol fee of the position tools, vaults and pre-market perps. 20 % is credited to the user's referrer; the rest belongs to the treasury, and anyone can flush it there. | ReferralRegistry, FeeCollector |
ReferralRegistry | deployAll | Write-once referral codes and write-once user-to-referrer links. | none |
FeeCollector | deployVenue | Receives the pools' protocol share and FeeRouter's flushes. Anyone can convert a token to ETH along the owner's route; the ETH goes to BuybackV2. | Router, AssetRegistry |
BuybackV2 | deployVenue | Spends up to 0.05 ETH per call on $LEVEE in its native-ETH v4 pool, burns every token bought and pays the caller 50 bps. poke moves its reference price. | PoolManager |
Details: Buyback and burn, Fees and referrals.
Who holds a key
| Role | Set from | Can | Cannot |
|---|---|---|---|
| Owner | OWNER, proposed by handOver, accepted with acceptOwnership | pause the venue, tune fees and price guards, list stocks, set fee routes, sweep FeeCollector, create pool vaults, name their keeper | touch a liquidity-management contract or a user position; block a withdrawal |
| Hedger | HEDGER, the address of the API's BOT_PRIVATE_KEY | reportHedge on hedged vaults, reportSleeve on notes, rebalance DLMM and stock vaults as their keeper | move vault funds |
| Funder, one per hedged vault | FUNDER_NVDA_HEDGED, FUNDER_SPY_HEDGED (default FUNDER), never a hot key or each other | fundHedge: send margin to its own Lighter account, at most 10 % of on-chain assets per call and 25 % per day; off chain, withdraw that margin | report equity |
| Order keys | generated by the signer, one per account | place and cancel Lighter orders | withdraw from Lighter |
DeployRobinhood refuses to run if the owner, hedger or a funder is the deployer, if a funder is the hedger, the keeper or the owner, or if the two hedged vaults share a funder.
The programs off chain
| Program | Code | Runs on | Job | Holds |
|---|---|---|---|---|
| Web app | apps/web | Next.js 15, wagmi, viem; Privy for email login, or RainbowKit when no Privy app id is set | Every page and every user transaction | nothing; your wallet signs |
| API | apps/api | Fastify on :8792; Postgres, or memory when DATABASE_URL is unset | The routes pages read, the perp proxy, Ideas and points | SIGNER_SECRET, ADMIN_SECRET |
| Bots | apps/api/src/bots | inside the API process, only when enabled | Seven loops: keeper, hedger, graduator and four pool duties | BOT_PRIVATE_KEY, the hedger |
| Indexer | apps/indexer | Ponder 0.16 on :42072; Postgres, or PGlite | Logs into tables, served as GraphQL to the API alone | nothing |
| Signer | services/signer | FastAPI on :8793 | Lighter onboarding and order signing, with no code path that withdraws | Lighter order keys, Fernet-encrypted |
Indexer, API and bots covers the first four in depth; Perpetuals covers the signer.
A write, from click to block
Every button that changes chain state calls useWrite().run(...) in apps/web/lib/tx.ts. There is no second path.
- 01Gate
canWritechecks for a connected wallet, chain 4663 (development builds also allow 31337) and a deployment manifest. If one is missing, the button says which. - 02SimulateThe hook runs
simulateContract, aneth_callfrom your address. A revert stops here: it costs nothing and your wallet never opens. - 03Sign and sendYour wallet signs the simulated request and sends it through the RPC. A toast links the transaction on the explorer.
- 04RefreshThe query keys the write affects are refetched at 1.5 s, 4 s and 10 s, the time the indexer needs to see the new logs.
For anything a transaction must get exactly right, the browser reads the chain directly instead of asking the API: balances, allowances, vault previews, router quotes, the active DLMM bin. The API never sends a transaction for a user. Its POST routes store a signed Idea, forward a signed perp request to the signer, return a mirror plan for your wallet to send, record the contact form or, with the admin secret, recompute points.
A read, from chain to page
- A page hook in
apps/web/lib/data.tscalls a typed fetcher inapps/web/lib/api.tsagainstNEXT_PUBLIC_API_URL(http://127.0.0.1:8792by default), with a 15 s stale time and no retry. - The API route answers from the indexer (GraphQL documents in
src/indexer/queries.ts), from chain reads batched through Multicall3, from market data (Lighter first, then Hyperliquid or Yahoo) or from its database. A cached route keeps its answer for 15 to 60 s. - The route maps its own model to the exact shape
api.tsdeclares (routes/wire.ts), and a test fails if either side renames a field. - If the API does not answer, a development or staging build shows a fixture with a "Sample data" tag. A production build never does: it shows the empty state and a status notice instead.
The indexer is fed by the chain alone. It subscribes to the Uniswap factory, position manager and PoolManager, to every Levee contract in the manifest, and to the Pons factory, and folds their logs into tables.
Shared packages
@levee/core
Pure TypeScript with no I/O, imported by the web, the API and the indexer. It holds tick maths and range shapes, zap maths, impermanent loss, fee APR, the Seasoned screen (isEstablished), Carry (basis.ts), LP delta and hedge sizing (hedge.ts), keeper policy predictions (policy.ts), note payoffs, DLMM bin maths, the perp request message (perpAuth.ts), slippage, market hours, position sizing and backtests. A number on a card and the number a bot acts on come from the same function.
Two Foundry tests write fixtures when run with WRITE_FIXTURES=true: contracts/fixtures/zap.json, which packages/core/src/zapMath.test.ts asserts the TypeScript port against, and contracts/fixtures/payoff.json, eight points of each StructuredVault.payoffCurve mode that payoff.ts mirrors.
@levee/abi and the manifest
src/generated/holds the compiler ABIs of every contract with an off-chain caller.contracts/export-abis.shwrites them, and they are committed, so no package needs Foundry to build.src/addresses.tsholds the fixed facts: chain 4663, the public RPC, the Uniswap contracts, tokens, Chainlink feeds, Lighter, Multicall3, Pons and the stock list.src/manifest.tstypes the deployment manifest and validates it withloadManifest, which names the bad key when it throws.
The manifest is the one file that says where a deployment lives: chainId, deployBlock, the owner, treasury, hedger and funder, each hedged vault's funder (funders), the three vault implementations, addresses (with seed vaults by name) and venue. The API reads it from MANIFEST_PATH, the indexer from PONDER_MANIFEST, the web from apps/web/deployments/manifest.json or NEXT_PUBLIC_MANIFEST_URL. Without one, writes are disabled, the bots stay off, the manifest routes answer empty and the indexer sees only Uniswap.
Deployed addresses
Read from the manifest this site loaded, so the table is always the deployment you are using:
Chain 4663, deployed from block 82,431,214. Each address opens on the explorer.
Deploying the stack
DeployRobinhood.s.sol and DeployLocal.s.sol both call deployAll in contracts/script/LeveeWiring.sol. It never starts a broadcast and never reads the environment, so the same sequence runs under a broadcast, a dry run and a fork test.
- 01The venue
VenueWiring.deployVenuedeploysAssetRegistry,BuybackV2,Router,FeeCollectorandProtocolConfig, then both hooks at CREATE2 addresses whose low bits are their permission flags, then the DLMM, launch and stock-vault contracts. It sets the quotes, lists every stock with default risk parameters and names the hedger as keeper of both vault factories. - 02Fees
ReferralRegistry, thenFeeRouterwith the venue'sFeeCollectoras its treasury. - 03Position toolsBoth zaps,
RangeOrdersandPositionKeeper. - 04Vaults and launchesThe three vault implementations, then
VaultFactory, which takes them as constructor arguments because their combined creation code is over the initcode limit. ThenLaunchPipelineandPreMarketPerp. - 05Seed vaultsBest effort: the ETH and USDG vaults on WETH/USDG 0.05 %, NVDA and SPY Hedged on each token's deepest WETH pool, Income NVDA and Protected SPY. A missing pool logs a line and skips that vault.
- 06Hand over
handOverproposes the owner for the four venue admin contracts. Until the owner callsacceptOwnership, the deployer still holds them.
writeManifest then records the result. DeployLocal also runs VenueSeed, which seeds pools, a deposit, a resting DLMM limit order and a launch on a local fork. Canary.s.sol is the post-deploy smoke test: a tiny zap, a range order placed and cancelled, and a harvest on the ETH vault's pool.
Reference
Deploy values
| Name | Allowed | Default | Effect |
|---|---|---|---|
CURVE_HALF_TICKS | ticks | 2231 | Half-width of every seed vault range (about ±25 %), snapped to the pool spacing. |
HYSTERESIS_SPACINGS | spacings | 10 | Seed vault hysteresis, as a multiple of tick spacing. |
MIN_INTERVAL | seconds | 6 h | Least time between two keeper actions on a seed vault. |
MAX_SLIPPAGE_BPS | bps | 100 | Swap bound on a seed vault rebalance. |
BOUNTY_BPS | bps | 50 | Bounty the seed vault policy advertises to bots. |
NO_CAP | asset units | type(uint256).max | The cap of the ETH and USDG vaults and both hedged vaults: none. |
PROTECTED_NOTE_CAP / INCOME_NOTE_CAP | WETH | NO_CAP / 0 | The Protected note opens with no cap; the Income note is not open yet. |
MAX_HEDGE_AGE | seconds | 1 h | A hedge or sleeve report older than this pauses the vault. |
MAX_EQUITY_JUMP_BPS | bps | 1500 | One report moving equity by more than 15 % pauses the vault. |
MAX_FUND_BPS_PER_CALL / PER_PERIOD | bps | 1000 / 2500 | fundHedge caps: 10 % of on-chain assets per call, 25 % per day. |
NOTE_TERM | seconds | 90 days | Maturity of both seed notes, counted from the deploy block. |
INCOME_SLEEVE_BPS / PROTECTED_SLEEVE_BPS | bps | 8000 / 8500 | Share of a note in its LP sleeve (Income) or in SGOV (Protected). |
MIN_LIQUIDITY | liquidity | 10 ether | In-range liquidity LaunchPipeline needs before a graduation, summed over four fee tiers. |
BUYBACK_MAX_ETH_PER_CALL | wei | 0.05 ETH | Most one buyback call may spend. |
STOCK_OPEN / CLOSED / STALE_FEE_BPS | bps | 30 / 150 / 500 | Default stock pool fee by session; the owner can tune each asset. |
STOCK_OPEN / CLOSED_MAX_DEV_BPS | bps | 200 / 50 | Default oracle band of a stock pool, open and closed. |
Ports and environment
| Program | Port | Points at |
|---|---|---|
| API | PORT 8792 | INDEXER_URL (http://127.0.0.1:42072), RPC_URL, MANIFEST_PATH, SIGNER_URL (http://127.0.0.1:8793) |
| Indexer | 42072 | PONDER_RPC_URL, PONDER_MANIFEST, DATABASE_URL |
| Signer | 8793 | SIGNER_SECRET, shared with the API |
| Web | 3000 (Next.js default) | NEXT_PUBLIC_API_URL, NEXT_PUBLIC_RPC_URL, NEXT_PUBLIC_CHAIN_ID, NEXT_PUBLIC_PRIVY_APP_ID |
contracts/src/the liquidity-management contracts and their librariescontracts/src/venue/pools, router, pool vaults, launches and the fee pathcontracts/script/LeveeWiring.soldeployAll, the seed vaults and writeManifestcontracts/script/venue/VenueWiring.soldeployVenue and handOverapps/web/lib/tx.tsuseWrite, the one write pathapps/web/lib/data.tspage hooks and the fixture rulepackages/core/src/the shared mathspackages/abi/src/manifest.tsthe manifest type and loadManifestcontracts/export-abis.shhow the generated ABIs are written