Architecture
What is built, as of 16 Sep 2026. The earlier six-layer sketch planned contracts that were never
written; this describes the ones that were. Why each is shaped this way lives in DECISIONS.md.
The map
Solid arrows are calls; dashed arrows are seams — an interface with nothing behind it yet. Everything inside the dotted box is created per launch; everything outside is shared by every launch.
The contracts
| Contract | Role | Instances | Upgrade path | Imports v4 |
|---|---|---|---|---|
LaunchFactory | Launches a token and its curve; the registry (launchOf); quote, fee and pool-share config | one | UUPS, owned (D2) | no |
BondingCurve | Buy and sell on virtual reserves, fees pushed per trade, graduates inside the crossing buy | one per launch | beacon, bound for life to the beacon current at launch (D12) | no |
LaunchToken | The ERC20. One extension point: an immutable, gas-capped observer | one per launch | none | no |
PoolMigrator | Opens the pool at launch, seeds it at graduation, holds the liquidity forever, collects and splits its fees | one per pool shape | replaced, never upgraded (D16) | yes |
FeeVault | The protocol's treasury, per currency; hands fees to a replaceable strategy | one | none; the strategy is the seam | no |
LaunchRouter | ETH or any token in and out of a launch, along a v3 path, on the curve or in the pool | one | UUPS, owned (D22) | yes |
BasketWrapper, BasketFactory | Stocks and baskets as quote assets (src/assets) | one per composition; one factory | wrapper none; factory UUPS | no |
src/assets and the core never import each other; the factory reaches baskets only through
IQuoteSource (D19, D20). make check-boundaries enforces it, and treats src/router as core.
A launch, end to end
A launch is only ever in one of four states:
- Launch.
LaunchFactory.launchdeploys the token and a curve proxy, and has the migrator open the pool empty at the price the curve will close at — in the same transaction, so nobody can open it first (D16). The migrator records the curve as the only address that may seed it (D24), with the creator's fee wallet and pool share (D25). - On the curve. Every buy and sell pushes the protocol's fee to the vault and the creator's to their wallet; a refused push is held and retryable by anyone (D17).
- Graduation. The buy that crosses the threshold locks the curve and calls
graduate(), which approves exact amounts and lets the migrator pull them into a full-range position. Short of the gas for that, the buy reverts rather than deferring, so wallet estimates include it (D23). - In the pool. A hookless v4 pool, quotable by aggregators. Anyone can call
collectFees, which splits both currencies between the creator's wallet and the vault.
The router sits beside all of this, never in it (D22): every launch stays directly tradable.
The seams
| Interface | What can be swapped behind it |
|---|---|
IQuoteSource | What a launch may be paired against beyond the owner's list — baskets today |
IMigrator | The pool a launch graduates into: a new migrator is a new pool shape, for new launches |
IFeeSink, IFeeStrategy | What happens to protocol fees once collected |
ITokenObserver | What watches a token's balances move |
Not yet per launch. The hook comes with the migrator, which is chosen per quote asset; the fee sink and the observer are global. Making all three per launch, isolated from each other, is the modular infrastructure effort experiments need (D26).
The local stack
make dev-deploy builds it on a bare anvil, in three steps:
| Step | What it deploys |
|---|---|
contracts/dev/uniswap-v3 | Uniswap v3 from official source, its own Foundry project: WETH9, factory, position manager, SwapRouter02 |
script/DevMarkets.s.sol | dUSD and dARB, and full-range v3 pools routing ETH into them |
script/Deploy.s.sol | The v4 PoolManager from source, the launchpad, the router; WETH, dUSD and dARB registered; fees on |
Addresses land in contracts/deploy/31337*.json. make dev-smoke drives the whole path against them.