Skip to main content

Launching an index

Launching is permissionless — anyone can create an index token from the app or by calling the factory directly. Every parameter below is fixed forever at launch, so choose deliberately.

From the app

The Create wizard walks through four steps:

  1. Basics — name, symbol, total supply.
  2. Basket — pick 1–16 tokenized stocks/ETFs from the governance allow-list (search box included). On testnet these are the 18 mock stocks (Mag 7 + AVGOx, COINx, MSTRx, AMDx, NFLXx, PLTRx, ORCLx, CRCLx, SPYx, QQQx, SOXXx); on mainnet the 25 official Robinhood Chain tokenized equities.
  3. Fees — the buy fee and sell fee (each ≤ 10%), plus the "RFV backing vs holder distribution" slider: how the 90% non-protocol share of every fee splits between the redeemable USDG floor and stock dividends (0–90% RFV; the protocol's 10% is fixed and shown separately).
  4. Review — confirm and submit. One transaction deploys everything.

What one launch deploys

IndexFactory.createIndex(cfg) performs, atomically:

  • Clones the immutable IndexToken implementation (EIP-1167 minimal proxy) and initializes it with your config — the initializer validates the fee cap, basket size, allow-list membership, duplicates, and rejects the reserve asset or the token itself as basket members.
  • Deploys a dedicated IndexTreasury (the RFV vault) bound to your token.
  • Mints supply: 1% → protocol treasury, 99% → you (the caller is always recorded as creator — it can't be spoofed).
  • Forwards the native launch fee (if FeeRegistry.launchFeeWei > 0).
  • Emits IndexCreated with the full config (including rfvShareBps), which the indexer picks up.

Launching from a contract or script

IndexConfig memory cfg = IndexConfig({
name: "Mag Seven",
symbol: "MAG7",
creator: address(0), // overwritten with msg.sender by the factory
totalSupply_: 1_000_000e18,
buyFeeBps: 300, // 3% buy fee (max 1000)
sellFeeBps: 300, // 3% sell fee (max 1000)
stocks: stocks, // 1..16 allow-listed stock token addresses
distributionMode: 0, // reserved; keep 0
rfvShareBps: 1500 // 15% of fees → RFV floor (0..9000)
});

(address token, address treasury) =
IndexFactory(FACTORY).createIndex{value: launchFee}(cfg);

Constraints enforced on-chain (reverting errors in parentheses):

ParameterConstraint
buyFeeBps / sellFeeBps≤ 1000 (10%) — immutable after launch
stocks1–16 entries (EmptyBasket / BasketTooLarge), no duplicates (DuplicateAsset), each on the FeeRegistry allow-list (AssetNotAllowed), never the reserve asset or the token itself
rfvShareBps0–9000 (RfvShareTooHigh) — immutable
totalSupply_> 0 (ZeroAmount)
msg.valueFeeRegistry.launchFeeWei (InsufficientLaunchFee)

After launch: make it tradable

The token starts fee-inert — fees only apply to trades against a registered AMM pair:

  1. Seed liquidity. Create an index/USDG pool on the chain's Uniswap v2-style DEX and add liquidity (you received 99% of supply).
  2. Register the pair. Call setAmmPair(pair, true) (creator-gated). The contract validates it is a genuine pool for this token (token0/token1 check) and marks it dividend-excluded so LP balances never soak up holder dividends.
Register before (or immediately after) seeding

The pair is dividend-excluded at registration and reserves are reconciled — but registering promptly keeps distribution accounting clean from the first trade.

  1. Trade. From here the fee lifecycle runs on its own: fees accrue, anyone converts, holders claim.

Choosing the RFV split

rfvShareBpsCharacter
0Pure dividend index — the full 90% buys stocks for holders
1500 (default)15% floor / 75% dividends — the classic $INDEX-style profile
9000Pure RFV index — all fees deepen the redemption floor; the stock-buy loop is skipped entirely

There is no wrong answer — it is a product decision about whether your index rewards holding via income (dividends) or holding via backing (a rising floor).