Skip to main content

IndexFactory

contracts/src/index/IndexFactory.sol — the permissionless launchpad. One singleton per chain; anyone can call createIndex. It is also the Uniswap V4 unlock callback that seeds each launch's liquidity.

On mainnet the factory is deployed behind a UUPS (ERC1967) proxy, so its creation logic and the per-launch token / bond / treasury implementation pointers can be upgraded in place under a stable address — protocol iteration no longer requires a fresh deployment. This is scoped strictly to creation: every index token, treasury, and governor the factory has already produced is an immutable clone/singleton and is never affected by a factory upgrade. Upgrades and impl repointing are owner-gated (a TimelockController on mainnet), and renounceOwnership is disabled so the upgrade path can never be accidentally frozen.

createIndex

function createIndex(IndexConfig calldata cfg, uint256 creatorBuyUsdg)
external payable
returns (address token, address treasury);

Atomically, in one transaction:

  1. Checks the registry isn't paused and the protocol treasury is wired.
  2. Overwrites cfg.creator with msg.sender — creatorship can't be spoofed.
  3. Clones the IndexToken at a CREATE2 address mined to sort above USDG (so USDG is currency0).
  4. Deploys the index's IndexTreasury and clones its BondDepository, wiring the depository as the treasury's one-shot inventory spender.
  5. initializes the token — the whole 1,000,000 supply mints to the factory.
  6. Initializes the USDG/index V4 pool at the launch tick (the 20k-mcap floor) and configures it on the IndexFeeHook.
  7. Seeds the full supply as single-sided stepped liquidity across the fixed curve (see below).
  8. Optionally runs a creator pre-buy — a real USDG→index market buy through the hook (approve the factory for creatorBuyUsdg first).
  9. Refunds any unconsumed index tokens to the creator, forwards the launch fee, emits IndexCreated + IndexLaunched.

msg.value must be ≥ FeeRegistry.launchFeeWei (InsufficientLaunchFee); any excess ETH is refunded.

The single-sided launch curve

There is no premine and no seeded USDG. The factory seeds the entire FIXED_SUPPLY as 5 stepped, index-only concentrated-liquidity positions — every position sits at or below the launch tick, so each owes only the index token (currency1). Buyers bring the USDG; the 20k-mcap floor is therefore a hard price floor.

The curve (from Constants.sol) walks from $0.02 (20k mcap) up to $1.00 (1M mcap):

PositionPrice band (USDG/token)Share of supply
P1$0.020 → $0.05030%
P2$0.050 → $0.12030%
P3$0.120 → $0.27920%
P4$0.279 → $0.59712%
P5$0.597 → $1.008%

The deep base near the floor defends the launch price; liquidity thins as price rises. Because USDG is currency0, a buy drives the tick down from the start tick toward 0 ($1.00).

The creator pre-buy

Passing creatorBuyUsdg > 0 executes a real market buy of the token for the creator in the same transaction — it pays the swap fee (and the launch snipe-guard rate) exactly like any other trade, and any USDG the swap doesn't consume is refunded. This replaces the old "founder allocation": there is no privileged pre-mint, only a market buy at the launch price.

Registry views

FunctionReturns
allTokens(uint256) / allTokensLength()Every index ever launched
isIndex(address)Whether an address is an IndexPad token
treasuryOf(address)The treasury bound to an index
bondOf(address)The bond depository bound to an index
tokensByCreator(address)Indexes launched by a creator

Events

event IndexCreated(
address indexed token,
address indexed creator,
address treasury,
string name,
string symbol,
address[] stocks,
uint16 rfvShareBps,
uint16 buybackShareBps
);

event IndexLaunched(
address indexed token,
bytes32 poolId,
uint256 creatorBuyUsdg,
uint256 creatorReceived
);

IndexCreated is the discovery root for the indexer — every clone is picked up here (Ponder factory pattern), so newly launched indexes appear in the app automatically.