Skip to main content

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

ContractKindRole
FeeRegistrySingletonGovernance config: reserve asset (USDG), PoolManager, protocol treasury, launch fee, stock allow-list, price feeds, bond bounds, guardian pause
IndexFactorySingletonPermissionless launchpad — clones the token (CREATE2-mined above USDG), deploys the treasury + bond depository, seeds the full supply single-sided
IndexFeeHookSingletonThe shared V4 hook on every index pool: takes the whole fee and runs the creator's 3-way split inline, per swap, keeper-free
V4SwapRouterSingletonMinimal exact-in router for the USDG/index pools (the chain ships a forked Universal Router, so trading routes through this)
TreasurySingletonInterim protocol fee sink (Ownable2Step; migrates to the $IPAD-redeemable ProtocolTreasury later)
IndexTokenPer index (clone)Fixed-supply (1,000,000), never-mintable burnable ERC-20 + basket metadata + 3-way split config
IndexTreasuryPer indexBacking vault: USDG reserve + basket stocks + index-token bond inventory; oracle-free multi-asset redeem()
BondDepositoryPer index (clone)OHM-style bonds that sell the treasury's index inventory (never mint); enabled by the creator later
ProtocolToken / ProtocolTreasuryIn repo, not deployedFuture $IPAD token + redeemable treasury — the migration target once $IPAD launches

Protocol constants

All in libraries/Constants.sol, enforced on-chain:

ConstantValueMeaning
FIXED_SUPPLY1,000,000e18Every index's supply — minted once, never mintable again
START_MCAP_USDG20,000 USDGLaunch market-cap floor ($0.02/token); no liquidity below it
CURVE_STEPS5Single-sided stepped positions seeded across the launch curve
PROTOCOL_BASE_FEE_BPS300.30% flat protocol fee on every swap's volume
PROTOCOL_SHARE_BPS100010% of the index fee → protocol (on top of the base fee)
NON_PROTOCOL_BPS9000The creator-splittable pool: rfvShareBps + buybackShareBps ≤ 9000, remainder buys stocks
BASE_BUY_FEE_BPS / BASE_SELL_FEE_BPS100 / 150Base index fee (1.0% buy / 1.5% sell), before the volatility term
MAX_DYNAMIC_FEE_BPS300Cap on the volatility-scaled index fee (3%)
LAUNCH_GUARD_BLOCKS / LAUNCH_GUARD_FEE_BPS2 / 500Snipe guard: 5% fee for the first 2 blocks after launch
REDEMPTION_SPREAD_BPS5005% spread kept in the vault on every redemption
MAX_BASKET_SIZE16Max basket stocks per index
DEFAULT_MAX_BOND_DISCOUNT_BPS1000Protocol cap on any index's bond discount (10%)
MIN_TWAP_WINDOW30 minMin 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)

ComponentWhereNotes
Indexer (Ponder + Postgres)RailwayRead-only event indexing for the app — API reference
Web app (Next.js + wagmi/viem)VercelUI 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.