Integration docs
What to read and call to list REA.fund launches and trade them: on their bonding curves, then in the locked Uniswap v4 pools they graduate into. Chains: Robinhood Chain.
A token launches with a fixed supply of 1,000,000,000 (18 decimals) on a bonding curve paired with a quote asset. Once the curve has raised its graduation threshold, the launch graduates: the raised quote and the tokens held back for it open one full-range position in a Uniswap v4 pool behind our hook, at the curve's final price, locked for good. Held-back tokens the position doesn't take are locked too and never trade.
Trading runs on Pons V2, byte-identical to the live Pons deployment on Robinhood Chain: if you already integrate Pons trades there, point the same code at our factory addresses. Launching goes through ReafundLauncher, which binds each launch to its project and gives it its own fee splitter.
Robinhoodchain id 4663RPC https://rpc.mainnet.chain.robinhood.comexplorerdeployed at block 90,281,269
Plus 192 Robinhood Stock Tokens; each approved one answers approvedPairTokens true.
Every launch is one event on the factory: index the factory from its deploy block. The event names the token, its bonding curve and its quote asset (a pairToken of the zero address is native ETH, on Robinhood Chain only). Every launch goes through the launcher, so the factory's deployer is always the launcher. The launcher's own event, in the same transaction, names the launching wallet, the open-source project the launch is bound to (keccak256 of github:<repository id>), its fee splitter, the creator fee and the project's share of it. The splitter pays the trade fee's part of what it receives to the protocol fee recipient and splits the rest, the creator fee, between the launcher and the project.
"event TokenLaunched(address indexed token, address indexed curve, address indexed deployer, address pairToken, uint256 launchConfigId, uint256 graduationThreshold)"
"event Launched(address indexed token, address indexed creator, bytes32 indexed projectId, address curve, address splitter, address quote, uint16 devShareBps, uint16 creatorTaxBps, uint256 quoteSpent, uint256 tokensOut)"
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.
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 or a Stock Token): approve the curve for
quoteIn, then callbuywith no value. - Native ETH quote: 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 trade fee and any creator fee taken from the input first, a buy gives tokensOut = ⌊tokenReserve × in′ / (quoteReserve + in′)⌋ where in′ = quoteIn − ⌊quoteIn × feeBps / 10000⌋ − ⌊quoteIn × taxBps / 10000⌋, less any snipe tax. A sell is the same curve in reverse, with the trade fee and creator fee 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 in 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 one slips through, anyone can call graduate(token) on the factory.
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 at the curve's final price, mints the full-range position and hands it to the locker (PoolGraduated, phase 2). The position can never be withdrawn. Swept tokens the position doesn't take at that price stay in the locker for good (GraduationTokensPermanentlyLocked).
"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 fee 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.
Robinhood
| Term | Value |
|---|---|
| Launch fee | 0.0005 ETH |
| Curve fee, per trade | 1% |
| Pool fee, per swap, taken by the hook | 1% |
| Snipe tax on buys, in the launch window | 99% at launch, falling to nothing over 3 seconds; the launching wallet pays none |
| Creator fee | 1% to 10% per trade for the token's life, set at launch; the least is signed into the binding, and only $REAFUND's own launch has none |
| Where the trade fee goes | All of it to the protocol fee recipient: 30% of each fee paid by Pons directly (currentFeePolicy().protocolFeeShareBps), the rest forwarded by the launch's ReafundFeeSplitter |
| Project's share of the creator fee | At least 50%, signed into the binding and fixed at launch (Launched.devShareBps); the rest is the launcher's, credited in the fee escrow |
| Protocol fee recipient (treasury) | 0x6fba0d0079302732515A945161fcF7d36818B6a5 |
| Developer vault, a payout address | Takes effect 3 days after it is proposed (NOTICE), executable by anyone for 7 days after that (EXECUTION_WINDOW) |
| A launch's creator fee recipient | The owner can change it after 3 days (CREATOR_FEE_RECIPIENT_TIMELOCK) |
| Graduation target, ETH | 4.2 ETH raised (about $10.2k today) |
| Graduation target, USDG | 8,090 USDG raised, over a phantom reserve of 3,236 |
| Graduation target, cbBTC | 0.09947 cbBTC raised, over a phantom reserve of 0.039788 |
| Graduation target, TAO | 29.37 TAO raised, over a phantom reserve of 11.748 |
| 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) |
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's issuer can pause it, block addresses, and burn or split it; a launch paired with one inherits that.
The contracts have an owner, and some pairs have an issuer. This is everything either can do to a launch.
- OwnerName a project's payout addressTo settle a dispute or recover a lost account, after 3 days of public notice. It can name any address, its own included: the notice is the guard. A project already paid can withdraw what is held before the change takes effect.
- OwnerRedirect a launch's creator feeChange where a launch's creator fee goes, the project's part with it, after 3 days of public notice, which Pons enforces.
- OwnerRescue a stalled graduationIf a graduated launch's pool still isn't created 7 days later, send its reserves to an address it chooses.
- OwnerChange the terms of future launchesThe trade fee, the launch fee, the creator fee cap, the graduation targets, the launch window and the approved pairs; a launch already made keeps its own. And hide a launch from this site, though it keeps trading on chain.
- IssuerPause, block or burn a Stock TokenRobinhood can do all three to its Stock Tokens, from any address, the fee escrow and the developer vault included. A launch paired with one inherits that.
What nobody can do
- Take a trading curve's reserves.
- Take a graduated pool's liquidity: it is locked for good.
- Change a launch's name, ticker, project or pair.
- Hold your funds or your keys: every transaction is yours.
Full JSON ABIs for the launchpad contracts, to share with exchanges and indexers.
- Launcher ABI (JSON)
- Fee splitter ABI (JSON)
- Developer vault ABI (JSON)
- Factory ABI (JSON)
- Bonding curve ABI (JSON)
- Launch token ABI (JSON)
- Pool hook ABI (JSON)
- Uniswap v4 PoolManager (events only) ABI (JSON)
Below, selected functions and events in the human-readable form ethers and viem's parseAbi take. Both come from the ABIs this site itself uses.
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)"