Multiplexmultiplex
Integration

Reading the chain

Everything a terminal, a bot or a chart needs is readable on Robinhood Chain, with no API key and nobody's permission.

Every number this app shows — price, market cap, curve progress, the trade tape — is derived from the chain. None of it is privileged: the same reads are open to anyone, and if this app disappeared tomorrow the data would still be there.

This page is the map. It is what you would implement to put a coin on a trading terminal.

Read it yourself rather than trusting a feed. Everything below is a public view call or an event log, so any number here can be reproduced from the chain at any block.

The two contracts that matter

LaunchPad created every coin and knows where each one trades. QuoteBookHook prices the leveraged stock tokens those coins are paired against.

You need both, because a coin's price is expressed in a leveraged token, and only the hook knows what that token is worth in dollars.

Finding every coin

The launcher keeps its own list, so there is nothing to crawl:

launchPad.tokenCount() -> uint256
launchPad.allTokens(i) -> address

For history, index the Launched event instead. It carries the metadata URI — the coin's image and links — which is deliberately not stored on chain, so the event is the only place it exists:

event Launched(
  address indexed token, address indexed pool, address indexed creator,
  uint256 supply, int24 tickLower, int24 tickUpper, uint128 liquidity, string metadataUri
);

Finding every market

The hook's books is a mapping and cannot be enumerated, so the list comes from events:

event BookRegistered(bytes32 indexed id, address indexed asset, uint256 assetUnit, bool numeraireIsCurrency0);

One per pool opened against the hook. Index those and you have every asset the venue makes a market in, including ones listed after you wrote your integration. Don't hard-code the set.

What state a coin is in

launchPad.launches(token) -> (
  address pool, int24 tickLower, int24 tickUpper, uint128 liquidity,
  bool tokenIsToken0, bool graduated, address creator, uint64 createdAt,
  uint256 threshold, uint16 reserveBps
)

launchPad.curveProgress(token) -> (uint256 raised, uint256 threshold)

graduated decides where you read the price from: the v3 curve pool before, the v4 pool after. raised / threshold is the progress bar, and both numbers come from the coin's own record — the threshold is fixed at launch, so a coin's finish line is whatever it was on the day it opened.

pool == address(0) means this launcher did not create that token. That is the check to run before showing anyone a coin address they were handed somewhere else.

Pricing a coin

Two steps, because a coin does not trade against dollars.

1. The coin's price in its pairing asset, from the pool's sqrtPriceX96:

ratio           = (sqrtPriceX96 / 2^96)^2      // token1 base units per token0 base unit
numeraire/coin  = tokenIsToken0 ? ratio : 1 / ratio

2. The pairing asset's price in dollars, from the book. buyPrice and sellPrice are USDG base units per 1e18 of the asset; the mid is the fair value between them:

hook.books(bookId) -> (uint128 buyPrice, uint128 sellPrice, uint64 updatedAt, ...)

Multiply the two and adjust for decimals: USDG is 6, coins and leveraged tokens are 18. That mismatch is the most common integration bug on this chain.

Two prices that both look right and are not the same number.

The pool's price is where the last trade left the pool. The execution price is what that trade paid. A buy that walks a long way up a curve pays its average on the way, well below where it ends up: one buy of 75% of a supply executed at $8.08e-7 and left the pool at $2.70e-6. Charts and market caps use the pool price; a fills tape uses execution. Mixing them misstates a coin threefold.

A price sitting on a tick boundary is not a price. A swap that exhausts a curve walks to the very end of the range, where sqrtPriceX96 squares to 3.4e38 — a coin apparently worth $2.8e37, seconds before it graduated. Treat the boundaries as "no price", not as a number.

Is the price live?

The book carries its own timestamp, and the venue refuses to trade on a stale one:

hook.books(id).updatedAt   // unix seconds of the last quote
hook.maxQuoteAge()         // how old a quote may be, in seconds

Quotes refresh roughly every 10 seconds. Past maxQuoteAge every fill reverts with QuoteStale() — so a price derived from an expired quote is a price nobody can actually trade at. hook.nav() reverts rather than returning a stale number, which makes it the safer read of the two.

The trade tape

Fills against the book emit an event that describes itself:

event Filled(
  bytes32 indexed poolId, address indexed sender, bool takerBuys,
  uint256 assetAmount, uint256 numeraireAmount, uint128 buyPrice, uint128 sellPrice
);

It carries the two quotes that fill executed against, so the price paid and the spread earned are computable from the log alone — you never have to reconstruct what the market looked like at that block. Anything derived from a current price would value every historic fill at today's number.

HookSwap is emitted alongside it for hook-aware indexers, following the usual convention: positive amounts flow into the hook, negative flow out, which is how you recover direction.

Coin trades are ordinary Uniswap events — v3 Swap on the curve, v4 on graduated pools. Keying history by token rather than by pool is what keeps a chart continuous through graduation: the venue underneath a coin changes, the coin does not.

Market cap and holders

Market cap is the pool price against totalSupply(), which is fixed at 1,000,000,000 and never changes — there is no mint function after launch.

Holder counts have to come from Transfer logs; nothing on chain keeps a count. Addresses belonging to the protocol — the curve position, the hook's own inventory, the redemption wallet — are holders in the ERC-20 sense but are not public float.

Fees

A graduated coin charges 1% on trades, of which 30% goes to the coin's creator. Both are readable rather than assumed:

feeHook.creatorBps() -> uint16
feeHook.treasury()   -> address

Want to trade, not just read?

The router is one call to buy or sell any coin, paying in ETH or USDG, with the whole route assembled for you.