Integration docs
What to read and what to call to list CooCoo launches and trade them: on their bonding curves first, then in the locked Uniswap v4 pools they graduate into. Chains: Robinhood Chain and Arc.
What it is
A token launches with a fixed supply of 1,000,000,000 (18 decimals) on a bonding curve paired with a quote asset. When the curve has raised its graduation threshold, the launch graduates: the raised quote and the tokens held back for it are placed as one full-range position in a Uniswap v4 pool behind our hook, and that position is locked for good. Trading happens on the curve until graduation and in the pool after it.
The contracts are Pons V2 without modification, byte-identical to the live Pons deployment on Robinhood Chain. If you already integrate Pons there, point the same code at our factory addresses. Two peripheral contracts on Arc carry a small patch for Arc's native USDC; they change no interface.
Addresses
Robinhoodchain id 4663RPC https://rpc.mainnet.chain.robinhood.comexplorerdeployed at block 63,606,612
Plus 192 Robinhood Stock Tokens; each approved one answers approvedPairTokens true.
Arcchain id 5042RPC https://rpc.mainnet.arc.iono public explorer yetdeployed at block 21,148,973
| FactoryPonsV2LaunchFactory | 0xc954f286027067dfce8b50dCE46dbe8D683E9002 |
| HookPonsV2MemeHook, on every graduated pool | 0x915bF3CB732Bb692D63EcA08f962D62221CFE044 |
| Launch-and-buy forwarder | 0xee6430930F1a47bc19b0Ccd988e6a060Ce763910 |
| Launch deployer | 0x6004695B5DDB67E715E5e04d38987D9FaeA5F9d8 |
| Lockerholds every pool position, for good | 0x29B591B2fe7e7e30fBbC273FDc054143edfCBd12 |
| Fee escrow | 0x21524873EFaB3Af236A35eA287099eD1fBe4c4cD |
| Buyback vault | 0x0659cBd25D738011c03F139222ee531dDB854e61 |
| Graduation executor | 0x5f4265F231b7f26a1B3a158c8Fbcf139FbCe5b05 |
| Graduation guard | 0xF839f84428f0ac687d89B557B206E122c3eAE12A |
| Uniswap v4 PoolManager | 0x8366a39cc670b4001a1121b8f6a443a643e40951 |
| Uniswap v4 PositionManager | 0x6049c9a0e26405c0985f9e3685c87d0ae917f82b |
| Universal Router | 0x4fca4a51ab4f23a7447b3284fbd7d73289a89fb1 |
| V4 Quoter | 0x8dc178efb8111bb0973dd9d722ebeff267c98f94 |
| StateView | 0xf3334192d15450cdd385c8b70e03f9a6bd9e673b |
| Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
| Quote: USDC6 decimals, the same balance as native gas | 0x3600000000000000000000000000000000000000 |
Discovering launches
Every launch is one event on the factory, from its deploy block onward. It names the token, its bonding curve and the quote asset it pairs with; a pairToken of the zero address is native ETH, on Robinhood Chain only.
"event TokenLaunched(address indexed token, address indexed curve, address indexed deployer, address pairToken, uint256 launchConfigId, uint256 graduationThreshold)"
Read a launch's state at any time from the factory:
"function getLaunchedToken(address token) view returns ((address token, address curve, address deployer, address creatorFeeRecipient, address pairToken, uint256 graduationThreshold, uint24 poolFee, int24 tickSpacing, uint16 creatorTaxBps, bool buybackEnabled, uint8 phase, uint256 sweptQuote, uint256 sweptTokens, uint256 sweptAt, bool exists))"
| phase | Meaning | Where it trades |
|---|---|---|
| 0 | NotGraduated | The bonding curve. |
| 1 | Swept: graduated, pool not yet created | Nowhere, for a block or two, until createGraduatedPool runs; anyone may call it, and our keeper does. |
| 2 | PoolCreated | The Uniswap v4 pool. |
| 3 | Rescued: an owner rescue after a stuck graduation | Treat as delisted. |
The token is a plain ERC-20 with name(), symbol(), 18 decimals, and views for the logo, description and socials its creator set at launch.
Trading on the curve
Each launch has its own curve contract. Two functions do all the trading, and both return the amount received, so an eth_call of the same call is an exact quote.
"function buy(uint256 quoteIn, uint256 minTokensOut, address recipient) payable returns (uint256 tokensOut)" "function sell(uint256 tokensIn, uint256 minQuoteOut, address recipient) returns (uint256 quoteOut)"
- ERC-20 quote (USDG, cbBTC, TAO, a Stock Token, Arc's USDC): approve the curve for
quoteIn, then callbuywith no value. - Native ETH quote (Robinhood Chain): call
buywithvalueequal toquoteIn. - Selling: approve the curve for
tokensIn, thensell. The quote comes back torecipient, native or ERC-20 as the pair is.
Pricing is constant-product over virtual reserves: quoteReserve() is the real quote plus a fixed phantom amount, tokenReserve() the tokens still on the curve. With the fee and any tax taken from the input first, a buy gives tokensOut = tokenReserve × in′ / (quoteReserve + in′) where in′ = quoteIn × (10000 − feeBps − taxBps) / 10000. A sell is the same curve in reverse, with the fee and tax taken from the proceeds. A buy larger than sellableTokens() is clamped and the unspent quote refunded in the same transaction.
Views for quoting, and the events for indexing trades:
"function getReserves() view returns (uint256 quoteReserve_, uint256 tokenReserve_)" "function quoteReserve() view returns (uint256 quoteReserve_)" "function tokenReserve() view returns (uint256 tokenReserve_)" "function phantomQuote() view returns (uint256)" "function feeBps() view returns (uint256)" "function creatorTaxBps() view returns (uint256)" "function currentSnipeTaxBps(address recipient) view returns (uint256)" "function sellableTokens() view returns (uint256)" "function graduationThreshold() view returns (uint256)" "function readyToGraduate() view returns (bool)" "function graduated() view returns (bool)" "event CurveBuy(address indexed buyer, address indexed recipient, uint256 quoteIn, uint256 tokensOut, uint256 fee, uint256 tax)" "event CurveSell(address indexed seller, address indexed recipient, uint256 tokensIn, uint256 quoteOut, uint256 fee, uint256 tax)" "event CurveBuyRefunded(address indexed buyer, uint256 refund)" "event CurveCompleted(address recipient, uint256 quoteOut, uint256 tokenOut)"
A buy that crosses the graduation threshold graduates the launch inside the same transaction. Send it with generous gas: a bare eth_estimateGas often lands on the path where that inner graduation runs out of gas and is caught, leaving the curve readyToGraduate(). We send the estimate plus a quarter plus 450,000. If it slips through, anyone can call graduate(token) on the factory.
Graduation and the pool
When the real quote reserve reaches graduationThreshold, the curve sweeps its reserves to the factory (LaunchSwept, phase 1). Then createGraduatedPool(token), callable by anyone, initialises the Uniswap v4 pool, mints the full-range position and hands it to the locker (PoolGraduated, phase 2). The position can never be withdrawn.
"event LaunchSwept(address indexed token, uint256 quoteOut, uint256 tokenOut)"
"event PoolGraduated(address indexed token, uint256 positionId, uint256 tokenAmount, uint256 pairTokenAmount)"
PoolKey {
currency0, currency1 = the token and the quote, sorted by address (native ETH is address(0))
fee = getLaunchedToken(token).poolFee
tickSpacing = getLaunchedToken(token).tickSpacing
hooks = the Hook address for that chain
}Trade the pool as any v4 pool: the Universal Router's V4_SWAP with SWAP_EXACT_IN_SINGLE, SETTLE_ALL and TAKE_ALL, Permit2 for ERC-20 input, and the V4 Quoter for quotes. The hook takes its fee and the creator's tax inside the swap and emits HookFeeCollected; a swap log's amounts are gross of that, so net the fee off the unspecified side when you index pool trades.
Fees and terms
Robinhood
| Term | Value |
|---|---|
| Launch fee | 0.0005 ETH |
| Curve fee, per trade | 1% |
| Pool fee, per swap, taken by the hook | 1% |
| Launch-window tax on buys | 99% at launch, falling to nothing over 3 seconds; addresses the creator exempted pay none |
| Creator tax | 0 to 10% per trade for the token's life, set at launch |
| Graduation target, ETH | 4.2 ETH raised (about $10.1k today) |
| Graduation target, USDG | 8,090 USDG raised, over a phantom reserve of 3,236 |
| Graduation target, cbBTC | 0.1049 cbBTC raised, over a phantom reserve of 0.04196 |
| Graduation target, TAO | 36.05 TAO raised, over a phantom reserve of 14.42 |
| Graduation target, Stock Tokens | Pegged per token when it was listed; read pairTokenEconomics for the exact figure |
| Supply | 1,000,000,000 tokens; the share held back for the pool is supply × phantom / (phantom + threshold) |
Arc
| Term | Value |
|---|---|
| Launch fee | 2 USDC, sent as native value |
| Curve fee, per trade | 1% |
| Pool fee, per swap, taken by the hook | 1% |
| Launch-window tax on buys | 99% at launch, falling to nothing over 3 seconds; addresses the creator exempted pay none |
| Creator tax | 0 to 10% per trade for the token's life, set at launch |
| Graduation target, USDC | 8,090 USDC raised, over a phantom reserve of 3,236 |
| Supply | 1,000,000,000 tokens; the share held back for the pool is supply × phantom / (phantom + threshold) |
Per-pair economics live on the factory: approvedPairTokens(address) and pairTokenEconomics(address). Native ETH's live in launch config 0, getLaunchConfig(0). A Stock Token can be paused, can block addresses and can be burned or split by its issuer; a launch paired with one inherits that. Circle can pause or blocklist USDC on Arc.
ABI
Human-readable, ready for ethers or viem's parseAbi, printed from the ABIs this site itself sends to. The full JSON ABIs are Pons V2's; ask and we'll send them.
Factory
"event TokenLaunched(address indexed token, address indexed curve, address indexed deployer, address pairToken, uint256 launchConfigId, uint256 graduationThreshold)" "event LaunchSwept(address indexed token, uint256 quoteOut, uint256 tokenOut)" "event PoolGraduated(address indexed token, uint256 positionId, uint256 tokenAmount, uint256 pairTokenAmount)" "function getLaunchedToken(address token) view returns ((address token, address curve, address deployer, address creatorFeeRecipient, address pairToken, uint256 graduationThreshold, uint24 poolFee, int24 tickSpacing, uint16 creatorTaxBps, bool buybackEnabled, uint8 phase, uint256 sweptQuote, uint256 sweptTokens, uint256 sweptAt, bool exists))" "function approvedPairTokens(address pairToken) view returns (bool approved)" "function pairTokenEconomics(address pairToken) view returns (uint256 phantomQuote, uint256 graduationThreshold, uint8 decimals)" "function launchEnabled() view returns (bool)" "function launchFee() view returns (uint256)" "function graduate(address token)" "function createGraduatedPool(address token) returns (uint256 positionId)"
Bonding curve, one per launch
"function buy(uint256 quoteIn, uint256 minTokensOut, address recipient) payable returns (uint256 tokensOut)" "function sell(uint256 tokensIn, uint256 minQuoteOut, address recipient) returns (uint256 quoteOut)" "function getReserves() view returns (uint256 quoteReserve_, uint256 tokenReserve_)" "function quoteReserve() view returns (uint256 quoteReserve_)" "function tokenReserve() view returns (uint256 tokenReserve_)" "function phantomQuote() view returns (uint256)" "function feeBps() view returns (uint256)" "function creatorTaxBps() view returns (uint256)" "function currentSnipeTaxBps(address recipient) view returns (uint256)" "function sellableTokens() view returns (uint256)" "function graduationThreshold() view returns (uint256)" "function readyToGraduate() view returns (bool)" "function graduated() view returns (bool)" "function pairToken() view returns (address)" "function token() view returns (address)" "event CurveBuy(address indexed buyer, address indexed recipient, uint256 quoteIn, uint256 tokensOut, uint256 fee, uint256 tax)" "event CurveSell(address indexed seller, address indexed recipient, uint256 tokensIn, uint256 quoteOut, uint256 fee, uint256 tax)" "event CurveBuyRefunded(address indexed buyer, uint256 refund)" "event CurveCompleted(address recipient, uint256 quoteOut, uint256 tokenOut)"
CooCoo is run by OpenLegion LLC. Questions: @CooCooParty on X. About · Terms