Architecture overview
Foundry project, Solidity 0.8.28 (via-IR), OpenZeppelin 5.x, Uniswap V4. Every index launch is a set of cheap contracts (an EIP-1167 token clone + a treasury + a bond-depository clone) wired to a handful of shared singletons — the most important of which is a single fee hook that runs on every index pool.
Contract inventory
| Contract | Kind | Role |
|---|---|---|
FeeRegistry | Singleton | Governance config: reserve asset (USDG), PoolManager, protocol treasury, launch fee, stock allow-list, price feeds, bond bounds, guardian pause |
IndexFactory | Singleton | Permissionless launchpad — clones the token (CREATE2-mined above USDG), deploys the treasury + bond depository, seeds the full supply single-sided |
IndexFeeHook | Singleton | The shared V4 hook on every index pool: takes the whole fee and runs the creator's 3-way split inline, per swap, keeper-free |
V4SwapRouter | Singleton | Minimal exact-in router for the USDG/index pools (the chain ships a forked Universal Router, so trading routes through this) |
Treasury | Singleton | Interim protocol fee sink (Ownable2Step; migrates to the $IPAD-redeemable ProtocolTreasury later) |
IndexToken | Per index (clone) | Fixed-supply (1,000,000), never-mintable burnable ERC-20 + basket metadata + 3-way split config |
IndexTreasury | Per index | Backing vault: USDG reserve + basket stocks + index-token bond inventory; oracle-free multi-asset redeem() |
BondDepository | Per index (clone) | OHM-style bonds that sell the treasury's index inventory (never mint); enabled by the creator later |
ProtocolToken / ProtocolTreasury | In repo, not deployed | Future $IPAD token + redeemable treasury — the migration target once $IPAD launches |
Protocol constants
All in libraries/Constants.sol, enforced on-chain:
| Constant | Value | Meaning |
|---|---|---|
FIXED_SUPPLY | 1,000,000e18 | Every index's supply — minted once, never mintable again |
START_MCAP_USDG | 20,000 USDG | Launch market-cap floor ($0.02/token); no liquidity below it |
CURVE_STEPS | 5 | Single-sided stepped positions seeded across the launch curve |
PROTOCOL_BASE_FEE_BPS | 30 | 0.30% flat protocol fee on every swap's volume |
PROTOCOL_SHARE_BPS | 1000 | 10% of the index fee → protocol (on top of the base fee) |
NON_PROTOCOL_BPS | 9000 | The creator-splittable pool: rfvShareBps + buybackShareBps ≤ 9000, remainder buys stocks |
BASE_BUY_FEE_BPS / BASE_SELL_FEE_BPS | 100 / 150 | Base index fee (1.0% buy / 1.5% sell), before the volatility term |
MAX_DYNAMIC_FEE_BPS | 300 | Cap on the volatility-scaled index fee (3%) |
LAUNCH_GUARD_BLOCKS / LAUNCH_GUARD_FEE_BPS | 2 / 500 | Snipe guard: 5% fee for the first 2 blocks after launch |
REDEMPTION_SPREAD_BPS | 500 | 5% spread kept in the vault on every redemption |
MAX_BASKET_SIZE | 16 | Max basket stocks per index |
DEFAULT_MAX_BOND_DISCOUNT_BPS | 1000 | Protocol cap on any index's bond discount (10%) |
MIN_TWAP_WINDOW | 30 min | Min observation history before the bond market-price TWAP is trusted |
Trust model
- Immutable per token: the 1M supply (never mintable), the basket,
rfvShareBps,buybackShareBps. The creator's only post-launch power is the per-index admin role — enabling/configuring bond markets within protocol bounds. No one can mint, change a fee split, or touch the backing. - Governance (registry owner): the stock allow-list, price feeds, PoolManager/treasury addresses, launch fee, bond bounds (max discount, TWAP liquidity floor), and a guardian pause (blocks new launches — never swaps, redemptions, or claims).
- Nobody: can mint the index token, alter a launched fee split, drain the backing, or block a holder's
redeem.
Off-chain stack (optional, non-trusted)
| Component | Where | Notes |
|---|---|---|
| Indexer (Ponder + Postgres) | Railway | Read-only event indexing for the app — API reference |
| Web app (Next.js + wagmi/viem) | Vercel | UI only; every action is a direct wallet transaction |
There is no keeper and no fee-processing cron — the fee split is part of every swap.