# size.fun documentation > size.fun is a memecoin launchpad on X Layer (chain 196), quoted in OKB. Every coin launches with a fixed supply of 1,000,000,000 onto a constant-product bonding curve seeded with a 30 OKB phantom reserve, trades there until 75 OKB has gone in, then graduates into a Uniswap v4 pool whose liquidity position is minted into a contract with no withdrawal function. There is no presale and no team allocation. Trades pay a 1% base fee split 30% protocol / 70% creator, plus an optional creator tax of up to 10%, identically before and after graduation. Generated from https://docs.size.fun. 9 pages. # A memecoin launchpad on X Layer > Every coin opens on a bonding curve, trades against OKB from its first second, and graduates into a Uniswap v4 pool whose liquidity is locked forever. Here is what that means for you. *https://docs.size.fun/ · size.fun documentation* --- size.fun is a launchpad for memecoins on **X Layer**, OKX's chain. A coin launched here has no presale, no team allocation and no liquidity to add. You pay a flat fee, and one second later the coin is trading against OKB at a price the contract sets. Anyone can buy it, including you. When enough has been bought, the coin graduates into a Uniswap v4 pool and its liquidity is locked permanently. Nobody — not the creator, not the protocol — can withdraw it. ## The life of a coin 1. **Launch** — Pay 0.01 OKB. A fixed supply of 1,000,000,000 tokens is minted straight onto a bonding curve. Trading opens in the same transaction. 2. **Curve** — Buys push the price up, sells push it down, on a formula nobody can adjust. About 71% of the supply is available here. 3. **Graduation** — Once 75 OKB has gone in, the curve closes for good and the remaining ~29% of supply seeds a Uniswap v4 pool. 4. **Locked** — The liquidity position is minted into a contract with no withdrawal function. The pool keeps charging 1% and paying it out the same way. Every coin follows exactly this path. There is no route that skips a step, no setting that changes the order, and no manual intervention anywhere in it. ## What is fixed the moment you launch Most of what determines whether a launch is fair is decided by the contract, not by whoever deployed it: - **The supply.** One billion tokens, minted once, all of it onto the curve. There is no mint function afterwards. - **The team's allocation.** Zero. A creator who wants tokens buys them from the curve like everyone else, at the same price everyone else pays. - **The opening price and the graduation price.** Both are set by the curve's parameters before a single trade happens. See [The bonding curve](https://docs.size.fun/curve). - **The liquidity.** Seeded automatically at graduation from what the curve took in, and locked forever. Nobody has a key to it. > **What a creator does control** > > Three things, all declared at launch and all visible on the coin's page: an optional **creator tax** of up to 10% on trades, which they receive in full; whether to run **buyback-and-lock**; and which wallet their fees are paid to. Nothing else. ## What you are actually buying A plain ERC-20 with a fixed supply. It has no transfer tax, no blacklist, no pause switch, no owner and no upgrade path. Fees are charged by the venue you trade on — the curve before graduation, the Uniswap pool after — and never by the token itself, so it behaves normally in every wallet and every other contract. The *coin* is not audited by anyone and the meme behind it is not vouched for by anyone. What the launchpad guarantees is mechanical: the supply, the price curve, the fee split and the locked liquidity. Everything else about a given coin is up to the people trading it. ## The two costs | Charge | Who pays | Where it goes | | --- | --- | --- | | **0.01 OKB launch fee** | The creator, once | The protocol | | **1% base fee** | Every buy and every sell | 30% protocol, 70% creator | | **0–10% creator tax** | Every buy and sell, if the creator set one | The creator, in full | The 1% is charged identically before and after graduation, so the economics do not change under you when a coin crosses over. [Fees and earnings](https://docs.size.fun/fees) has the full breakdown, including the tax on the opening seconds that makes sniping a launch unprofitable. ## Reading this with an LLM Every page here is also served as Markdown at the same URL with `.md` appended — `/curve.md`, `/launch.md`, and so on. **Copy as Markdown**, beside the title of every page, puts that page on your clipboard; **Copy llms.txt** in the header puts the index of the whole site on it. Both are ready to paste into a model as they are. | File | What it is | | --- | --- | | [`/llms.txt`](https://docs.size.fun/llms.txt) | The index: what size.fun is in one paragraph, then every page with a one-line description. Start here if you are pointing an agent at these docs. | | [`/llms-full.txt`](https://docs.size.fun/llms-full.txt) | Every page concatenated into one file, about 60 KB. For when fetching nine URLs is worse than reading one. | | `/.md` | One page on its own, with the code samples as fenced blocks. | These are generated from the same source as the pages you are reading, in the same build, so they cannot fall behind. The addresses in them come from the deployed address book rather than from prose. ## Where to go next - [Quickstart](https://docs.size.fun/quickstart) — Get a wallet on X Layer and make your first trade. No code. - [The bonding curve](https://docs.size.fun/curve) — How the price is set, and where graduation lands. - [Fees and earnings](https://docs.size.fun/fees) — What each trade costs and what a creator takes home. - [Build with TypeScript](https://docs.size.fun/setup) — Launch and trade programmatically with viem. --- # Quickstart > Get a wallet onto X Layer, buy your first coin, or put one of your own on the board. Five minutes, no code. *https://docs.size.fun/quickstart · size.fun documentation* --- Everything on size.fun happens on **X Layer**, chain 196. If your wallet has never been there, adding it takes one prompt — the site offers it the first time you connect. ## Get a wallet onto X Layer Any EVM wallet works. OKX Wallet and MetaMask are the two most people use here. 1. Open [size.fun](https://size.fun/#/home) and hit **Connect**. 2. Pick your wallet from the list. Wallets announce themselves, so what you see is what is actually installed rather than a guess. 3. Approve the network prompt. If you decline it you stay connected, you just cannot trade until you switch. - **Network name**: X Layer - **Chain ID**: 196 - **Currency**: OKB - **RPC**: https://xlayerrpc.okx.com - **Explorer**: https://www.oklink.com/xlayer On the web page this is a button that asks the wallet to add the network (`wallet_addEthereumChain`). Add it by hand with the values above. The button adds the network to a wallet already installed in this browser. If nothing happens, your wallet is on your phone or is not exposing itself to this page — add the network by hand from the values above, or just connect at [size.fun](https://size.fun/#/home), which offers the same prompt. ## Fund it with OKB OKB is the gas token and the asset every coin trades against. Two ways to get some onto X Layer: - **Withdraw from OKX** and pick X Layer as the network. Usually the cheapest route. - **Bridge from Ethereum** through the official X Layer bridge. Blocks are one second and fees are a fraction of a cent, so you do not need to hold much for gas. What you bring is what you trade with. ## Buy a coin 1. Open a coin from the board. The page shows its price, its market cap and how far along its curve it is. 2. Enter an amount of OKB and hit **Buy**. You are trading against the curve, not against another person — there is no order book and no counterparty to wait for. 3. Confirm in your wallet. It lands in the next block. Selling is the same in reverse: enter an amount of the coin, approve it once, then sell. The curve always quotes a price, so a sell never fails for lack of a buyer. > **⚠ The first 15 seconds** > > A buy landing in the opening seconds of a launch pays an extra tax that starts at **99%** and decays to nothing within 15 seconds. It exists to make sniping a launch pointless. If you are not a bot, you will never notice it — just do not rush a brand-new coin. ## Launch a coin 1. Hit **Launch** in the sidebar. 2. Give it a name, a ticker, an image and a description. Socials are optional and go on the coin's page. 3. Set a **creator tax** if you want one — 0 to 10% of every trade, paid to you on top of your share of the base fee. Most launches leave it at 0. 4. Pay the 0.01 OKB launch fee. Trading opens in the same transaction. You get no free tokens. If you want a position in your own coin, buy it from the curve — and buy it in the *same transaction* as the launch, which the site does for you when you enter a dev buy. That closes the window a sniper would otherwise use. See [Launch a token](https://docs.size.fun/launch) for the same thing in code. ## Collect what you earn Fees from your coin accumulate on its curve as you trade. Getting them into your wallet is two steps, both on the [creator dashboard](https://size.fun/#/creator): 1. **Sweep** the curve. This splits the pending fees and moves your share into the escrow. 2. **Claim** from the escrow. One claim collects everything you are owed across every coin you have launched, before and after graduation. The escrow pays whoever calls it, so there is no address to type and nothing to send to the wrong place. [Claiming](https://docs.size.fun/fees#claiming) covers it in detail. --- # The bonding curve > One formula sets the opening price, the price of every trade after it, and the exact point the coin graduates. Nobody sets a price by hand and nobody adds liquidity. *https://docs.size.fun/curve · size.fun documentation* --- Before graduation a coin has no order book and no liquidity providers. It trades against a **bonding curve**: a contract holding the entire supply, which sells tokens for OKB and buys them back, at a price it works out from a single formula. The formula is constant product — the same one an AMM uses. The curve keeps a quote balance and a token balance, and their product never changes: quote × tokens = constant Buy, and OKB goes in while tokens come out. The token side shrinks, the quote side grows, and the price — the ratio between them — rises. Sell, and it runs backwards. Nobody adjusts anything; there is no setting for it. ## The phantom reserve A curve that started with zero OKB in it would price the first token at zero. So every launch starts with a **phantom reserve** of 30 OKB: a quote balance the contract counts for pricing but that nobody deposited and nobody can withdraw. It is the only number that needs choosing, and everything else follows from it: | Term | Value | Where it comes from | | --- | --- | --- | | Phantom reserve | 30 OKB | Set by the launchpad. Virtual. | | Graduation threshold | 75 OKB | Set by the launchpad. Real OKB in. | | Supply | 1,000,000,000 | Minted once, entirely onto the curve. | | Opening market cap | 30 OKB | Equal to the phantom reserve. | | Sold on the curve | 71.43% | 75 ÷ (30 + 75) | | Reserved for the pool | 28.57% | 30 ÷ (30 + 75) | | Price at graduation | 12.25× | ((30 + 75) ÷ 30)² | | Market cap at graduation | 367.5 OKB | (30 + 75)² ÷ 30 | So a coin opens at a 30 OKB market cap and graduates at 367.5 OKB, having taken in 75 OKB of real money. Every coin on the board, without exception, has those same three numbers. ## What a trade costs Price impact is whatever constant product says it is: a buy that takes 10% of the tokens off the curve moves the price about 23%, and one that takes half of them moves it fourfold. Early buyers get a better price than late ones, and the curve is public before anyone trades, so that is a fact of the design rather than a surprise in it. Walking a launch from open to graduation: | OKB in | Progress | Supply sold | Price (OKB) | Market cap (OKB) | | --- | --- | --- | --- | --- | | 0 | 0% | 0 | 0.0000000300 | 30.0 | | 7.5 | 10% | 200,000,000 | 0.0000000469 | 46.9 | | 15 | 20% | 333,333,333 | 0.0000000675 | 67.5 | | 37.5 | 50% | 555,555,556 | 0.0000001519 | 151.9 | | 60 | 80% | 666,666,667 | 0.0000002700 | 270.0 | | 75 | 100% | 714,285,714 | 0.0000003675 | 367.5 | Figures are before fees. The 1% base fee comes off the OKB leg of every trade in both directions, so reaching the 75 OKB threshold takes about 75.76 OKB of gross spending. [Fees and earnings](https://docs.size.fun/fees) has the rest. ## Selling You can sell back to the curve at any point before it graduates, for whatever the formula prices your tokens at. There is no lockup, no vesting and no cooldown on a coin you bought. The one moment selling is closed is the instant the curve runs out of sellable supply and before its pool exists — a window of one transaction, and a permissionless one: anyone can settle the graduation themselves and trade the pool instead. Nothing gets stuck. ## The last buy The curve stops at exactly 71.43% of supply sold. The remainder is the graduated pool's allocation and the curve will not sell into it. A buy that would cross that line is **filled up to it and refunded the difference**, rather than rejected. You get the tokens that were left, you are charged only for those, and the rest of your OKB comes back in the same transaction. The alternative — reverting — would let anyone grief the final buy of a launch by slipping a small trade in ahead of it. Your slippage bound still applies to a partial fill, read as a bound on the *price* you paid rather than on the quantity you received. A fill you were not charged for cannot fail a minimum you set for a fill you were. ## Progress The progress bar on a coin's page is the OKB sitting on the curve measured against the 75 OKB threshold. At 100% the coin graduates. A sell takes OKB back off the curve, so progress falls as well as rises — a coin at 90% is not 90% of the way to a guaranteed outcome. > **Reading it live** > > Price, market cap and progress are all derived from the curve's two balances, which means they can be read straight off the contract at any moment. [Trade a token](https://docs.size.fun/trade#quoting-a-trade) shows how. --- # Fees and earnings > Two charges per trade, one split between the protocol and the creator and one paid to the creator alone — plus a tax on the opening seconds that exists to make sniping unprofitable. *https://docs.size.fun/fees · size.fun documentation* --- There are two charges on a trade, and they are independent. The **base fee** is 1%, always, and it splits between the protocol and the creator. The **creator tax** is 0–10%, set by the creator when they launch, and it goes to them in full. Both come off the OKB leg regardless of which way you are trading, so a fee is never denominated in the memecoin and a creator's earnings never depend on the coin they launched holding its value. ## The base fee | Share | Of the 1% | Goes to | | --- | --- | --- | | 30% | 0.30% of the trade | The protocol | | 70% | 0.70% of the trade | The creator | On a 1 OKB buy that is 0.01 OKB of fee: 0.003 to the protocol, 0.007 to whoever launched the coin. The split is frozen into each launch at the moment it is created, so a later change to the protocol's terms cannot reach back and reprice a coin that is already trading. ## The creator tax A creator may add up to **10%** on top, charged on every buy and sell of their coin and paid to them entirely — the protocol takes no part of it. It is declared in the launch transaction and cannot be changed afterwards. It is shown on the coin's page before you trade. A 10% tax is legal here and also obvious, which is the point: the number is on the contract and on the screen rather than buried in a token's transfer function. > **Worth knowing** > > The launchpad caps the creator tax at 10% today, and the contracts cap base fee plus creator tax at 20% combined regardless of what that setting is ever moved to. Most launches set no tax at all. ## The opening seconds A third charge exists and only ever applies to the first 15 seconds of a launch. A buy landing in the launch second pays **99%**; that decays to zero across the window, and after 15 seconds it is gone permanently. It exists to make sniping unprofitable. A bot that buys a brand-new curve in the same block it was created spends almost its whole budget on fees and gets almost no tokens for it, which is exactly the outcome that makes the strategy not worth running. Sells are never taxed by it. Two categories of wallet are exempt, both declared inside the launch transaction itself, before anyone else can see the coin exists: - The creator and their fee recipient, automatically. - Any wallets the creator names at launch — the sanctioned route for a team bundling its opening buys across several addresses, up to 32 of them. The tax that a sniper does pay is not burned. It joins the base fee bucket and splits 30/70 like everything else, so it ends up with the protocol and the creator. ## Buyback and lock A creator can opt in, at launch or afterwards, to putting **half of their own share** of the base fee into buying their coin back. That is 35% of the 1% — 0.35% of every trade. The protocol's 30% is never touched by it, and neither is the creator tax. Bought-back tokens are not burned. They go into a vault on a **five-year vest**, released gradually to the creator over that period. So the buyback is a commitment rather than a supply cut: the tokens come off the market for years, and the creator's own payout is what funds it. If the curve is too thin for the buyback to execute without moving the price too far, it folds back into the creator's ordinary payout instead of forcing a bad trade. ## Claiming Fees reach a wallet in two hops, and it is worth knowing why, because a creator looking at a full "pending" column and an empty "claimable" one is one transaction away rather than owed nothing. 1. **Charged** — A trade books its fee onto the coin's own curve, where it sits as pending — split between nobody yet. 2. **Swept** — A sweep splits the pending balance and credits each side's escrow account. The creator can call it themselves. 3. **Claimed** — A claim pays out. One call collects everything owed, across every coin, before and after graduation. The escrow **pays whoever calls it**. There is no recipient argument, so there is no address to type and nothing to send to the wrong place — and it is why the fee screens can be public without the money being. Creators do all of this at the [creator dashboard](https://size.fun/#/creator). One exception: a curve with a buyback earmarked needs a price floor on its sweep, which only the protocol's sweep operator can set, so those are swept for you rather than by you. The 0.01 OKB launch fee is the one charge that never enters the escrow — it goes straight to the protocol as the coin is created. ## After graduation The Uniswap v4 pool a coin graduates into charges the **same 1%** and splits it the **same 30/70**, through a hook shared by every graduated pool. The creator tax carries across too. So the economics do not change when a coin crosses over. A creator keeps earning on every swap for as long as the pool trades, and it lands in the same escrow balance the curve fees did — one claim covers both. --- # Graduation > When the curve sells its last available token it closes for good and the coin moves to a Uniswap v4 pool. The liquidity position is minted straight into a contract with no withdrawal function. *https://docs.size.fun/graduation · size.fun documentation* --- A coin graduates when its curve has sold every token it was allowed to sell — the 71.43% of supply that was on offer, reached at 75 OKB taken in. There is no vote, no approval and no waiting period. The transaction that buys the last token starts it. ## What happens 1. **The curve closes** — Buying and selling stop permanently. Pending fees are split and credited to the escrow. 2. **Reserves move** — The 75 OKB and the 28.57% of supply the curve was holding back are handed over to seed the pool. 3. **The pool opens** — A Uniswap v4 pool is created at the graduation price and a full-range position is minted into it. 4. **The position locks** — The position NFT is minted straight into a contract that has no withdrawal function of any kind. Both amounts were fixed before the coin ever traded. The curve was collecting OKB — the pool's own quote asset — from the very first buy, so seeding needs no swap, no price oracle and no discretion about what the pool opens at. ## The liquidity is locked, permanently The position is not held by the creator, not held by a multisig, and not held by the protocol with a promise not to touch it. It is minted into a contract whose code contains no function that can move it — no withdraw, no transfer, no emergency exit, nothing behind a timelock. Ownership of that contract exists only to have wired it to the factory once, and cannot be used to take a position out. Practically: a graduated size.fun coin cannot be rugged by pulling its liquidity, because there is no code path that pulls it. > **Verify it yourself** > > Read [LaunchLocker](https://docs.size.fun/contracts) on OKLink. The contract is verified — the absence of a withdrawal function is something you can check rather than something you have to be told. ## Fees carry across unchanged Every graduated pool shares one Uniswap v4 hook, and it charges the same **1%** on swaps and splits it the same **30% protocol / 70% creator**. A creator tax carries over at the rate the coin launched with. Fees land in the same escrow balance the curve's did, so a creator's single claim collects both. Nothing about their earnings changes at the boundary — which is the reason the split was designed to be the same on both sides of it. ## Trading a graduated coin It is an ordinary Uniswap v4 pool from that point. You can trade it on size.fun, or through any interface or router that speaks v4 on X Layer. The curve contract still exists but will never fill another trade. What changes for you as a trader: - **Price is set by the pool**, not by the launch formula. It can go below the graduation price — a curve's floor does not follow the coin across. - **Depth is real.** The pool holds the 75 OKB the curve took in, as liquidity that can never be withdrawn. - **Anyone can add liquidity** alongside it, but nobody can remove the launchpad's own position. ## If graduation does not land in one go Graduation is two phases: the curve's reserves are swept, then the pool is seeded. Normally both happen inside the buy that crossed the line. When the second phase does not land — a transient failure, or the buyer running out of gas — the coin sits swept and unsettled, and **anyone can finish it** by calling the pool creation themselves. It is permissionless and retryable, and it costs nothing but gas. This is deliberate. Making the last buyer solely responsible for a step that can fail would mean a launch could stall on one wallet's gas limit. --- # Setup > Install viem, define X Layer, and point a client at the launchpad. Every other page in this section starts from this file. *https://docs.size.fun/setup · size.fun documentation* --- Everything here uses [viem](https://viem.sh) and nothing else. The launchpad has no SDK to install — it is a handful of contracts, and viem is enough to call all of them. ```bash npm install viem ``` You will want TypeScript 5.0 or later, and Node 20 or later if you are running this outside a browser. The samples use top-level `await`, so run them as ESM — `"type": "module"` in your `package.json`, or a `.mts` file. ## The shared module Every other page imports from this file: the chain, the clients, the addresses and the ABIs. Save it once and the rest is a handful of lines each time. ```ts size.ts import { createPublicClient, createWalletClient, defineChain, http, parseAbi } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import type { Address } from 'viem' /** X Layer. Chain 196, native OKB, one-second blocks. */ export const xLayer = defineChain({ id: 196, name: 'X Layer', nativeCurrency: { name: 'OKB', symbol: 'OKB', decimals: 18 }, rpcUrls: { default: { http: ['https://xlayerrpc.okx.com'] } }, blockExplorers: { default: { name: 'OKLink', url: 'https://www.oklink.com/xlayer' } }, }) export const publicClient = createPublicClient({ chain: xLayer, transport: http() }) /** A server-side signer. In a browser use custom(provider) instead — see below. */ export const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) export const walletClient = createWalletClient({ account, chain: xLayer, transport: http() }) export const size = { factory: '0xfdfCaaF9e744D2C43365a710628469bCAf365491', launchAndBuy: '0x24274B859C2B99358A7c9ed1da33EbAb832CadB4', feeEscrow: '0x401100747741364AD16a96D6Ba5724Bf817Cc25F', } as const satisfies Record /** Coins quote against native OKB, which is addressed as the zero address. */ export const OKB = '0x0000000000000000000000000000000000000000' as const /** The only launch config on the factory today: 1B supply, 1% fee, 30/75 OKB. */ export const LAUNCH_CONFIG_ID = 0n export const factoryAbi = parseAbi([ 'struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }', 'struct TokenParams { string name; string symbol; string logo; string description; Socials socials; address creatorFeeRecipient; uint16 creatorTaxBps; bool buybackEnabled; bytes32 expectedEconomics; bytes32 salt; }', 'struct LaunchedToken { 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 launchFee() view returns (uint256)', 'function launchEnabled() view returns (bool)', 'function maxCreatorTaxBps() view returns (uint256)', 'function previewLaunchEconomics(uint256 launchConfigId, address pairToken) view returns (bytes32)', 'function launchToken(TokenParams params, uint256 launchConfigId, address pairToken) payable returns (address token, address curve)', 'function getLaunchedToken(address token) view returns (LaunchedToken)', 'function createGraduatedPool(address token) returns (uint256 positionId)', 'event TokenLaunched(address indexed token, address indexed curve, address indexed deployer, address pairToken, uint256 launchConfigId, uint256 graduationThreshold)', 'event PoolGraduated(address indexed token, uint256 positionId, uint256 tokenAmount, uint256 pairTokenAmount)', ]) export const launchAndBuyAbi = parseAbi([ 'struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }', 'struct TokenParams { string name; string symbol; string logo; string description; Socials socials; address creatorFeeRecipient; uint16 creatorTaxBps; bool buybackEnabled; bytes32 expectedEconomics; bytes32 salt; }', 'function launchAndBuy(TokenParams params, uint256 launchConfigId, address pairToken, uint256 quoteIn, uint256 minTokensOut, address recipient, address[] snipeTaxExemptions) payable returns (address token, address curve, uint256 tokensOut)', ]) export const curveAbi = parseAbi([ '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 realQuoteReserve() view returns (uint256)', 'function sellableTokens() view returns (uint256)', 'function graduationThreshold() view returns (uint256)', 'function currentSnipeTaxBps(address recipient) view returns (uint256)', 'function graduated() view returns (bool)', 'function readyToGraduate() view returns (bool)', 'function token() view returns (address)', 'function feeBps() view returns (uint256)', 'function creatorTaxBps() view returns (uint256)', 'function quoteFeeBalance() view returns (uint256)', 'function sweepFees(uint256 minBuybackTokensOut)', '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)', ]) export const escrowAbi = parseAbi([ 'function claim() returns (uint256)', 'function balanceOf(address recipient) view returns (uint256)', ]) ``` The ABIs are written as human-readable signatures rather than pasted JSON. viem parses them into the same thing, and they stay legible — which matters here, because these signatures *are* the reference for what you can call. > **Only the parts you need** > > These are trimmed to what the guides use. The contracts are verified on [OKLink](https://docs.size.fun/contracts), so the full ABI of any of them is one click away if you need something that is not here. ## Which RPC The public endpoint above works and is free. Two things to know about it: - It caps `eth_getLogs` at **100 blocks** per call. Fine for watching, painful for walking history — page it, or use a provider without the cap. - It is rate limited. If you are polling reads for more than a few coins, get your own endpoint. Everything on these pages is standard JSON-RPC, so any X Layer provider works. ## In a browser The only thing that changes is where the signature comes from. Reads still go through a public client; writes go through the user's wallet instead of a private key. ```ts browser.ts import { createWalletClient, custom } from 'viem' import { xLayer } from './size.js' /** * In a browser the signer is the user's wallet, so the private key never * exists in your code. Everything else on these pages is unchanged: the same * ABIs, the same simulate-then-write pattern, the same public client for reads. */ export async function connect() { const provider = (window as any).ethereum if (!provider) throw new Error('No wallet found') const [address] = await provider.request({ method: 'eth_requestAccounts' }) // Offer X Layer if the wallet has never been there. 0xc4 is 196. await provider.request({ method: 'wallet_addEthereumChain', params: [{ chainId: '0xc4', chainName: 'X Layer', nativeCurrency: { name: 'OKB', symbol: 'OKB', decimals: 18 }, rpcUrls: ['https://xlayerrpc.okx.com'], blockExplorerUrls: ['https://www.oklink.com/xlayer'], }], }).catch(() => {}) const walletClient = createWalletClient({ account: address, chain: xLayer, transport: custom(provider), }) return { address: address as `0x${string}`, walletClient } } ``` > **⚠ Keys** > > The server-side client in `size.ts` reads a private key from the environment. Never ship that to a browser, and never commit it. If you are building a UI, the wallet is the signer and your code never sees a key at all. ## What you can call | You want to | Call | On | | --- | --- | --- | | Launch a coin | `launchToken` | LaunchFactory | | Launch and take the first position | `launchAndBuy` | LaunchAndBuy | | Buy on the curve | `buy` | the coin's curve | | Sell on the curve | `sell` | the coin's curve | | Read price and progress | `getReserves` | the coin's curve | | Find a coin's curve | `getLaunchedToken` | LaunchFactory | | Settle a stalled graduation | `createGraduatedPool` | LaunchFactory | | Move fees to the escrow | `sweepFees` | the coin's curve | | Collect your fees | `claim` | FeeEscrow | Curve addresses are per coin. Given a token address, `getLaunchedToken` on the factory returns its curve along with the terms it launched under. --- # Launch a token > One call creates the token and its curve. A second form does that and takes the first position in the same transaction, which is the one you want if you are buying your own launch. *https://docs.size.fun/launch · size.fun documentation* --- A launch is one call to the factory with the coin's metadata, the launch config to use, and the launch fee attached. It deploys the token, deploys its curve, mints the whole supply onto it and opens trading — all in that transaction. ## The parameters Everything the launch needs, in one object. Most of it is metadata; three fields are decisions. ```ts launch-params.ts import { toHex } from 'viem' import { account } from './size.js' /** CREATE2 salt. It only has to be unused by this account — any random 32 bytes. */ const salt = toHex(crypto.getRandomValues(new Uint8Array(32))) export const params = { name: 'Example Coin', symbol: 'EXAMPLE', // A URL, not the image itself. Host the picture and put its link here — // uploading through size.fun gives you one, pinned to IPFS. logo: 'https://size.fun/api/img/0000000000000000000000000000000000000000000000000000000000000000', description: 'A coin that exists.', socials: { twitter: 'https://x.com/example', telegram: '', discord: '', website: '', farcaster: '', }, // Where this launch's fees are paid. Changeable later, by this address only. creatorFeeRecipient: account.address, // 0 to 1000, charged on every trade on top of the 1% base fee and paid to you // in full. Frozen at launch: there is no setter for it afterwards. creatorTaxBps: 0, // Puts half of your share of the base fee into buying the coin back, on a // five-year vest. Can be turned on or off later. buybackEnabled: false, // 32 zero bytes waives the check on the launch terms. See "Pinning the terms". expectedEconomics: `0x${'00'.repeat(32)}` as `0x${string}`, salt, } as const ``` | Field | What it does | | --- | --- | | `name`, `symbol` | Standard ERC-20 metadata. Permanent. | | `logo` | A URL. The contract stores the link, not the image, so host it somewhere that will outlive the launch. | | `description`, `socials` | Shown on the coin's page. All five social fields exist; pass empty strings for the ones you are not using. | | `creatorFeeRecipient` | Where this launch's fees are paid. Can be transferred later, by that address. | | `creatorTaxBps` | **Permanent.** 0–1000 (0–10%), charged on every trade on top of the base fee and paid to you in full. | | `buybackEnabled` | Puts half your share of the base fee into buying the coin back on a five-year vest. Changeable later. | | `expectedEconomics` | Pins the launch terms. 32 zero bytes waives it — see below. | | `salt` | Feeds CREATE2, so it must be one this account has not used. Any random 32 bytes. Mining it is how you get a vanity address. | ## Launching ```ts launch.ts import { parseEventLogs } from 'viem' import { publicClient, walletClient, account, size, factoryAbi, OKB, LAUNCH_CONFIG_ID, } from './size.js' import { params } from './launch-params.js' const launchFee = await publicClient.readContract({ address: size.factory, abi: factoryAbi, functionName: 'launchFee', }) // Simulating first does two things: it reverts here rather than on chain if // anything about the parameters is wrong, and it hands back the token and curve // addresses before the transaction has been sent. const { request, result } = await publicClient.simulateContract({ address: size.factory, abi: factoryAbi, functionName: 'launchToken', args: [params, LAUNCH_CONFIG_ID, OKB], value: launchFee, account, }) const [token, curve] = result console.log({ token, curve }) const hash = await walletClient.writeContract(request) const receipt = await publicClient.waitForTransactionReceipt({ hash }) // The same two addresses, read back off the receipt. const [launched] = parseEventLogs({ abi: factoryAbi, eventName: 'TokenLaunched', logs: receipt.logs, }) console.log(launched.args) ``` Simulating before writing is worth the extra round trip on this call in particular: the factory validates the whole parameter set, and a simulation tells you which constraint you missed with the actual error, rather than costing you a reverted transaction to find out. It also hands back the token and curve addresses before anything is sent, because both are CREATE2-derived and therefore knowable in advance. ## Launching and buying in one transaction The factory cannot fold a dev buy into `launchToken`, so doing it in two transactions leaves a gap between the coin opening and your buy landing. That gap is measured in blocks for a bot and in seconds for a human holding a wallet prompt, and it is long enough to lose the whole allocation — a launch on this factory was bought out by twenty-two addresses in the two blocks after it opened. `LaunchAndBuy` closes it outright. Both legs settle in one transaction, so there is no intermediate state to trade against, and a failed buy takes the launch down with it rather than leaving you holding a coin you did not want on its own. ```ts launch-and-buy.ts import { parseEther } from 'viem' import { publicClient, walletClient, account, size, factoryAbi, launchAndBuyAbi, OKB, LAUNCH_CONFIG_ID, } from './size.js' import { params } from './launch-params.js' /** What you want to spend on your own coin, in OKB. */ const quoteIn = parseEther('0.5') const launchFee = await publicClient.readContract({ address: size.factory, abi: factoryAbi, functionName: 'launchFee', }) const { request, result } = await publicClient.simulateContract({ address: size.launchAndBuy, abi: launchAndBuyAbi, functionName: 'launchAndBuy', args: [ params, LAUNCH_CONFIG_ID, OKB, quoteIn, // No slippage bound is needed. The curve does not exist until this call // creates it, so there is no price for anyone else to move first. 0n, // Who receives the tokens. Exempted from the snipe tax automatically. account.address, // Extra wallets to exempt, if a team is bundling its opening buys. Up to 31. [], ], // For a native launch the call carries both legs: the fee and the buy. value: launchFee + quoteIn, account, }) const [token, curve, tokensOut] = result console.log({ token, curve, tokensOut }) const hash = await walletClient.writeContract(request) await publicClient.waitForTransactionReceipt({ hash }) ``` > **Use this one** > > If you intend to hold any of your own coin, launch through `launchAndBuy`. The plain `launchToken` path is for launches with no dev buy at all. ### Bundling several wallets Buys in the first 15 seconds pay the [snipe tax](https://docs.size.fun/fees#the-opening-seconds). The recipient of the dev buy is exempted automatically; a team opening across several addresses passes them in `snipeTaxExemptions`, up to 31 more. They are declared inside the launch transaction, so they are fixed before anyone else can see the coin exists. ```ts args: [ params, LAUNCH_CONFIG_ID, OKB, quoteIn, 0n, account.address, ['0xabc…', '0xdef…'], // exempt as well; recipient is added for you ], ``` ## Pinning the terms The launch terms — supply, base fee, phantom reserve, threshold, the graduated pool's fee tier and the fee split — are protocol settings. They move rarely, but if one moved between your reading it and your launch mining, your coin would quietly get terms you did not agree to. `expectedEconomics` makes that revert instead. Read the digest, pass it, and a launch under changed terms fails rather than repricing. ```ts pin-economics.ts import { publicClient, size, factoryAbi, OKB, LAUNCH_CONFIG_ID } from './size.js' /** * The launch terms — supply, fee, phantom reserve, threshold, the pool's fee * tier, the fee split — are protocol settings. They change rarely, but a change * landing between the moment you read them and the moment your launch mines * would silently give you different terms than the ones you agreed to. * * Passing this digest as `expectedEconomics` makes that case revert instead. * Passing 32 zero bytes waives the check, which is what the site does. */ export const expectedEconomics = await publicClient.readContract({ address: size.factory, abi: factoryAbi, functionName: 'previewLaunchEconomics', args: [LAUNCH_CONFIG_ID, OKB], }) ``` Passing 32 zero bytes waives the check, which is what the site does. For a scripted launch where nobody is watching the prompt, pinning is the better default. ## After it lands Trading is already open — there is no second step to enable it. From here: - The coin's page is `https://size.fun/#/token/`. - Fees start accruing on the curve from the first trade. [Collecting them](https://docs.size.fun/trade#collecting-fees) is two calls. - `getLaunchedToken(token)` on the factory returns the curve address and the terms the launch is running under, at any time. > **⚠ Errors worth recognising** > > `CreatorTaxTooHigh` — above the 10% cap. `LaunchFeeNotPaid` — the value sent does not match `launchFee()`. `LaunchEconomicsMismatch` — the terms moved under a pinned launch. A repeated `salt` reverts too, because the pair already exists at that address. --- # Trade a token > Buying and selling on the curve, priced before you send it, with a slippage bound you set — and what changes once the coin has graduated. *https://docs.size.fun/trade · size.fun documentation* --- Before graduation you trade against the coin's own curve contract, not against a router and not against another person. Two functions, `buy` and `sell`, both taking a slippage bound and a recipient. ## Finding the curve Every coin has its own curve. Given the token address, the factory has the rest: ```ts const launch = await publicClient.readContract({ address: size.factory, abi: factoryAbi, functionName: 'getLaunchedToken', args: [token], }) launch.curve // the bonding curve to trade against launch.creatorTaxBps // the extra fee this coin charges, if any launch.phase // 0 curve, 1 swept, 2 pool created, 3 rescued ``` ## Quoting a trade Price the trade before you send it. The curve's arithmetic is short enough to reproduce exactly, so you can show a number that matches what will land — no allowance for rounding needed. ```ts quote.ts import type { Address } from 'viem' import { publicClient, curveAbi } from './size.js' const BPS = 10_000n /** * Prices a buy exactly as the curve will, so you can show a number before the * wallet prompt and set a slippage bound against it. * * The three charges come off the OKB leg first, and what is left is priced * against the reserves by constant product. `recipient` matters because the * snipe tax is per-wallet: a creator's own address is exempt, a stranger's is * not, and after the first 15 seconds of a launch it is zero for everyone. */ export async function quoteBuy(curve: Address, quoteIn: bigint, recipient: Address) { const read = { address: curve, abi: curveAbi } as const const [reserves, feeBps, taxBps, snipeBps, sellable] = await Promise.all([ publicClient.readContract({ ...read, functionName: 'getReserves' }), publicClient.readContract({ ...read, functionName: 'feeBps' }), publicClient.readContract({ ...read, functionName: 'creatorTaxBps' }), publicClient.readContract({ ...read, functionName: 'currentSnipeTaxBps', args: [recipient] }), publicClient.readContract({ ...read, functionName: 'sellableTokens' }), ]) const [quoteReserve, tokenReserve] = reserves const fee = (quoteIn * feeBps) / BPS const tax = (quoteIn * taxBps) / BPS const snipeTax = (quoteIn * snipeBps) / BPS const net = quoteIn - fee - tax - snipeTax let tokensOut = (net * tokenReserve) / (quoteReserve + net) // The curve will not sell into the graduated pool's allocation. A buy past it // is filled up to it and the unspent OKB comes back in the same transaction. const partialFill = tokensOut > sellable if (partialFill) tokensOut = sellable return { tokensOut, fee, tax, snipeTax, partialFill } } /** The same, in the other direction. Fees come off the OKB output here. */ export async function quoteSell(curve: Address, tokensIn: bigint) { const read = { address: curve, abi: curveAbi } as const const [reserves, feeBps, taxBps] = await Promise.all([ publicClient.readContract({ ...read, functionName: 'getReserves' }), publicClient.readContract({ ...read, functionName: 'feeBps' }), publicClient.readContract({ ...read, functionName: 'creatorTaxBps' }), ]) const [quoteReserve, tokenReserve] = reserves const gross = (tokensIn * quoteReserve) / (tokenReserve + tokensIn) const fee = (gross * feeBps) / BPS const tax = (gross * taxBps) / BPS return { quoteOut: gross - fee - tax, fee, tax } } ``` Three things this gets right that a naive quote does not: - **Fees come off the input first.** On a buy, all three charges are deducted from the OKB before anything is priced against the reserves. On a sell they come off the output. - **The snipe tax is per wallet.** Exempt addresses read zero, and after a launch's first 15 seconds everyone does. - **A buy can be clamped.** The curve will not sell into the graduated pool's allocation, so a large buy near the end fills partially and refunds the rest. ## Buying ```ts buy.ts import { parseEther } from 'viem' import type { Address } from 'viem' import { publicClient, walletClient, account, curveAbi } from './size.js' import { quoteBuy } from './quote.js' export async function buy(curve: Address, okb: string, slippageBps = 100n) { const quoteIn = parseEther(okb) const { tokensOut } = await quoteBuy(curve, quoteIn, account.address) const minTokensOut = (tokensOut * (10_000n - slippageBps)) / 10_000n const { request } = await publicClient.simulateContract({ address: curve, abi: curveAbi, functionName: 'buy', // quoteIn must equal the value sent — a native launch takes both. args: [quoteIn, minTokensOut, account.address], value: quoteIn, account, }) const hash = await walletClient.writeContract(request) return publicClient.waitForTransactionReceipt({ hash }) } await buy('0x0000000000000000000000000000000000000000', '0.25') ``` Two things the contract insists on: - `quoteIn` must equal the value sent. The curve checks it rather than inferring one from the other. - `recipient` is who receives the tokens, and it is also whose snipe-tax exemption is checked. Buying to an address that is not your own is fine, but it is that address's rate that applies. ### Slippage on a partial fill When a buy is clamped to what is left, `minTokensOut` is read as a bound on the **price** rather than on the quantity — the requirement is that what you paid per token is no worse than what your own arguments implied. Where nothing is clamped, it reduces exactly to `tokensOut >= minTokensOut`. So a bound sized against a full fill will not fail a partial one. You get the tokens that were there, at a price no worse than you asked for, and the unspent OKB comes back in the same transaction. ## Selling Selling moves tokens into the curve, so it needs an ERC-20 approval first. Buying does not — that leg is native OKB. ```ts sell.ts import { erc20Abi, parseEther } from 'viem' import type { Address } from 'viem' import { publicClient, walletClient, account, curveAbi } from './size.js' import { quoteSell } from './quote.js' export async function sell(curve: Address, amount: string, slippageBps = 100n) { const tokensIn = parseEther(amount) const token = await publicClient.readContract({ address: curve, abi: curveAbi, functionName: 'token', }) // Selling moves tokens into the curve, so it needs an allowance. Buying does // not — that leg is native OKB. const allowance = await publicClient.readContract({ address: token, abi: erc20Abi, functionName: 'allowance', args: [account.address, curve], }) if (allowance < tokensIn) { const { request } = await publicClient.simulateContract({ address: token, abi: erc20Abi, functionName: 'approve', args: [curve, tokensIn], account, }) const approval = await walletClient.writeContract(request) await publicClient.waitForTransactionReceipt({ hash: approval }) } const { quoteOut } = await quoteSell(curve, tokensIn) const minQuoteOut = (quoteOut * (10_000n - slippageBps)) / 10_000n const { request } = await publicClient.simulateContract({ address: curve, abi: curveAbi, functionName: 'sell', args: [tokensIn, minQuoteOut, account.address], account, }) const hash = await walletClient.writeContract(request) return publicClient.waitForTransactionReceipt({ hash }) } ``` You can sell at any point before the curve graduates. The one closed moment is the single transaction between the curve selling out and its pool existing, and it is permissionless to settle: call `createGraduatedPool(token)` on the factory yourself and trade the pool instead. ## Reading live state Price, market cap and progress are all derived from the curve's two balances. Nothing is stored, so nothing can be stale. ```ts state.ts import { formatEther, erc20Abi } from 'viem' import type { Address } from 'viem' import { publicClient, curveAbi } from './size.js' const WAD = 10n ** 18n /** * Price, market cap and progress are not stored anywhere — they are the curve's * two balances, read live. Which is why they are correct the instant a trade * lands rather than whenever something last indexed it. */ export async function curveState(curve: Address) { const read = { address: curve, abi: curveAbi } as const const [reserves, real, threshold, token, graduated] = await Promise.all([ publicClient.readContract({ ...read, functionName: 'getReserves' }), publicClient.readContract({ ...read, functionName: 'realQuoteReserve' }), publicClient.readContract({ ...read, functionName: 'graduationThreshold' }), publicClient.readContract({ ...read, functionName: 'token' }), publicClient.readContract({ ...read, functionName: 'graduated' }), ]) const [quoteReserve, tokenReserve] = reserves const supply = await publicClient.readContract({ address: token, abi: erc20Abi, functionName: 'totalSupply', }) // OKB per token, at 18 decimals. const price = (quoteReserve * WAD) / tokenReserve return { token, graduated, price: formatEther(price), marketCap: formatEther((price * supply) / WAD), raised: formatEther(real), progressPct: Number((real * 10_000n) / threshold) / 100, } } ``` ## Watching trades ```ts watch.ts import { formatEther } from 'viem' import type { Address } from 'viem' import { publicClient, curveAbi } from './size.js' /** Every buy and sell on one curve, as it lands. */ export function watchTrades(curve: Address) { return publicClient.watchContractEvent({ address: curve, abi: curveAbi, onLogs: (logs) => { for (const log of logs) { if (log.eventName === 'CurveBuy') { const { recipient, quoteIn, tokensOut } = log.args console.log(`BUY ${formatEther(quoteIn!)} OKB -> ${formatEther(tokensOut!)} by ${recipient}`) } if (log.eventName === 'CurveSell') { const { recipient, tokensIn, quoteOut } = log.args console.log(`SELL ${formatEther(tokensIn!)} -> ${formatEther(quoteOut!)} OKB by ${recipient}`) } } }, }) } ``` Blocks are one second on X Layer, so this is close to real time. Note that the public RPC caps log queries at 100 blocks, which matters if you page backwards through history rather than tailing. ## Collecting fees If you launched the coin, its fees accumulate on the curve as it trades. Getting them into your wallet is a sweep and then a claim. ```ts claim.ts import { formatEther } from 'viem' import type { Address } from 'viem' import { publicClient, walletClient, account, size, curveAbi, escrowAbi, } from './size.js' /** * Step one. Splits a curve's pending fees and credits the escrow. Callable by * the launch's fee recipient. Skip it for a graduated coin — the pool's hook * sweeps its own. * * The argument is a minimum output for the buyback swap, and only matters on a * curve with buyback enabled. Those are swept by the protocol's operator, since * only it can set that floor. */ export async function sweep(curve: Address) { const pending = await publicClient.readContract({ address: curve, abi: curveAbi, functionName: 'quoteFeeBalance', }) if (pending === 0n) return const { request } = await publicClient.simulateContract({ address: curve, abi: curveAbi, functionName: 'sweepFees', args: [0n], account, }) const hash = await walletClient.writeContract(request) await publicClient.waitForTransactionReceipt({ hash }) } /** * Step two. Pays out everything owed to the caller, across every coin they have * launched, from both curves and graduated pools. * * There is no recipient argument and there could not be one: the escrow pays * whoever called it. */ export async function claim() { const owed = await publicClient.readContract({ address: size.feeEscrow, abi: escrowAbi, functionName: 'balanceOf', args: [account.address], }) console.log(`claimable: ${formatEther(owed)} OKB`) if (owed === 0n) return const { request } = await publicClient.simulateContract({ address: size.feeEscrow, abi: escrowAbi, functionName: 'claim', account, }) const hash = await walletClient.writeContract(request) return publicClient.waitForTransactionReceipt({ hash }) } ``` One claim collects everything you are owed across every coin you have launched, from curves and graduated pools alike. See [Claiming](https://docs.size.fun/fees#claiming). ## After graduation The curve is closed for good and the coin is an ordinary Uniswap v4 pool. The functions on this page will revert with `CurveGraduated`. Check before you route: ```ts const launch = await publicClient.readContract({ address: size.factory, abi: factoryAbi, functionName: 'getLaunchedToken', args: [token], }) if (launch.phase === 0) { // Still on the curve. buy() and sell() above. } else if (launch.phase === 2) { // Graduated: swap through any v4 router on X Layer. } else { // 1 is mid-graduation — anyone can finish it with createGraduatedPool(token). // 3 is a launch the protocol unwound; it has no pool and never will. } ``` Swapping a graduated pool is standard Uniswap v4 — the pool key is the coin and OKB, at the tick spacing and fee tier the launch recorded, with the size.fun hook attached. The hook takes the same 1% and splits it the same way, so your effective cost per trade does not change across the boundary. --- # Contracts > Every deployed address on X Layer, what each one is for, and the live launch parameters they are configured with. *https://docs.size.fun/contracts · size.fun documentation* --- Every address below is on **X Layer, chain 196**, and every one is verified on OKLink. The source is what is deployed; you can read it rather than take this page's word for anything on it. ## Launchpad | Contract | Address | What it is | | --- | --- | --- | | **LaunchFactory** | `0xfdfCaaF9e744D2C43365a710628469bCAf365491` | Creates every coin and its curve, holds the launch terms, and runs graduation. This is the contract you call to launch. | | **LaunchAndBuy** | `0x24274B859C2B99358A7c9ed1da33EbAb832CadB4` | Creates a coin and buys its curve in a single transaction, so there is no window between the two for anyone to trade against. | | **FeeEscrow** | `0x401100747741364AD16a96D6Ba5724Bf817Cc25F` | Holds every recipient's claimable balance. Pays whoever calls claim(), so there is no recipient argument to get wrong. | | **MemeHook** | `0x48AB5124B299c4C437eE6B3A03325FF3B9b56044` | The Uniswap v4 hook every graduated pool shares. Charges the same 1% on swaps and splits it the same way the curve did. | | **LaunchLocker** | `0x2de052028A272f77763906A68c5a5372000f4eD9` | Holds the graduated liquidity position. It has no withdrawal function of any kind. | | **BuybackVault** | `0x9e4ddfC7c772c1C8E055233C08a9E4dBeC31F873` | Holds bought-back supply on a five-year vest, for creators who opt into buyback-and-lock. | | **GraduationExecutor** | `0xdc306AcBbD096c9266DB712f8737a78596341Bc9` | Mints the full-range v4 position at graduation and sends the NFT to the locker. | | **LaunchDeployer** | `0x1aaD1c0363E3D84d1Ad96a8F5A91df353cFC6C1E` | Deploys the token and curve pair at their CREATE2 addresses on the factory's behalf. | | **GraduationGuard** | `0xC0C31995B318eDA8B5776Cc94192932B39E0cD6f` | Blocks liquidity being added to a graduated pool outside the launchpad's own position. | The two you will actually call are **LaunchFactory**, to launch, and each coin's own **bonding curve**, to trade. Curves are deployed per coin — find one with `getLaunchedToken(token)` on the factory. ## Per-coin contracts Two contracts are created for every launch, at addresses derived from the creator's account and their chosen salt: | Contract | What it is | | --- | --- | | **SizeLauncherToken** | The coin. A fixed-supply ERC-20 with no owner, no mint, no pause and no transfer tax. Carries the logo, description and socials as read-only metadata. | | **SizeBondingCurve** | Holds the whole supply and prices every trade until graduation. Where `buy` and `sell` live. | ## Uniswap v4 The canonical X Layer deployment. Graduated pools live inside it. | Contract | Address | What it is | | --- | --- | --- | | **PoolManager** | `0x360E68faCcca8cA495c1B759Fd9EEe466db9FB32` | Uniswap v4 singleton. Every graduated pool lives inside it. | | **PositionManager** | `0xcF1EAFC6928dC385A342E7C6491d371d2871458b` | Mints the full-range position graduation seeds. | | **Permit2** | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | Canonical Permit2, used by the position manager. | ## Live parameters What the factory is configured with today. These are protocol settings and can be changed for future launches — a coin freezes the terms it launched under, so a change never reaches back to one that is already trading. | Parameter | Value | What it is | | --- | --- | --- | | Chain | X Layer (chain 196) | Where every contract lives. | | Quote asset | OKB | Native OKB. | | Supply | 1,000,000,000 | Fixed at launch. | | Launch fee | 0.01 OKB | Paid once, when the coin is created. | | Base trade fee | 1% | Every buy and sell, before and after graduation. | | Phantom reserve | 30 OKB | Virtual OKB setting the opening price. | | Graduation threshold | 75 OKB | Real OKB in before the curve closes. | | Pool tick spacing | 200 | The graduated Uniswap v4 pool. | | Fee term | Value | | --- | --- | | Protocol share of the base fee | 30% | | Creator share of the base fee | 70% | | Buyback share, when enabled | 50% of the creator's share | | Maximum creator tax | 10% | | Hard cap, base fee + creator tax | 20% | | Snipe tax, opening rate | 99% | | Snipe tax window | 15 seconds | | Buyback vest | 5 years | ## Network - **Chain**: X Layer - **Chain ID**: 196 - **Currency**: OKB - **RPC**: https://xlayerrpc.okx.com - **Explorer**: https://www.oklink.com/xlayer - **Block time**: ~1 second - **Log query cap**: 100 blocks per call ## Provenance These contracts are a port of [Pons](https://www.ponsfamily.com/launchpad) v2, which is MIT licensed and verified on Robinhood Chain. The mechanics are the original's; what changed is the denomination — repriced from ETH to OKB, preserving the ratio that gives the curve its shape — and the name. > **⚠ Read this before you size a position** > > These contracts are not audited. They are verified, and their source is a port of a deployed and reviewed original, but neither of those is an audit. The launchpad's mechanics are what this documentation describes; the coins launched on it are not vetted by anyone, and most of them will go to zero.