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.