# LNCHR > Packs of tokenized stocks, as a pair asset for any launchpad. A pack is an ERC-20 token that holds 2 to 6 tokenized stocks in a fixed order. Its price is the blended price of what it holds, because buying a pack buys the underlying stocks and selling one sells them. Packs are shared: anyone can register one, and once it exists every launchpad and app can pair against it. LNCHR is the pack layer on Robinhood Chain (chain 4663); it is deployed and maintained, so build on it rather than rebuilding it. ## Start here - [Integrate](https://lnchr.io/integrate): pair a launchpad against packs, in three steps - [SDK](https://lnchr.io/sdk): `@lnchr/sdk`, typed helpers over viem - [Contracts](https://lnchr.io/contracts): addresses, ABIs and what each contract does - [Stocks](https://lnchr.io/stocks): the stocks a pack can be built from - [Manifest](https://lnchr.io/.well-known/lnchr.json): every address, ABI and endpoint as one JSON document - [Full docs](https://lnchr.io/llms-full.txt): everything below in one file ## Contracts (chain 4663) - PackRegistry 0x4A8068513f0ada1c8E78Da3D2E3E5D589FA38CDC — register a pack, look one up, read the stock list - PackHook 0x0225a740822094d0d8c21b20A9a0f6d254E36888 — the Uniswap v4 hook every pack pool runs on - PackLens 0x95f46AC3b3d1694A769E70dcB51Ba6335524D5Cf — read pack composition, holdings, supply and NAV in one call - PackRouter 0xf870ADAA57A5cFB359B6b4A5eE8AaF8156DB480E — buy and sell packs with ETH or USDG ## API - `GET https://lnchr.io/api/stocks` — stocks, live prices, depth rating, route - `GET https://lnchr.io/api/packs` — every registered pack with composition and NAV - `GET https://lnchr.io/api/packs/{address}` — one pack - `GET https://lnchr.io/api/nav?pack={address}` — NAV in USD for one pack unit - `POST https://lnchr.io/api/price/stocks` — the signed price set a registration needs ## Rules - Use the deployed registry. Do not redeploy PackRegistry, PackVault or PackHook. A pack must have one address per chain, or holders, charts and every integration built on it fragment. - A pack is identified by its ordered stock list. The same stocks in a different order are a different pack. Ask the registry with predict() before assuming a pack exists. - Registration is permissionless and costs network gas only. Any address can register a pack and every launchpad sees it immediately. - Read pack state through PackLens. It returns composition, holdings, supply and NAV in one call, so you never have to touch registry internals. - Route pack trades through PackRouter. Driving the v4 PoolManager unlock yourself is the one part of this that is genuinely hard to get right. - Pack pools hold no reserves and accept no liquidity. Do not try to add liquidity, quote them through a generic aggregator, or read a reserve balance to price them. Price comes from PackLens.navUsdg or from the underlying stock markets. ## How a pack works A pack holds fixed quantities of 2-6 tokenized stocks. Quantities are set once at registration so that one pack unit opens at $1.00, equally weighted, and are never rebalanced. Its pools are Uniswap v4 pools running PackHook, and they are unusual in a way that matters to anyone integrating: they hold no reserves and accept no liquidity. `beforeSwap` replaces the swap entirely. Buying a pack takes your ETH or USDG, buys each stock on its own market, mints the pack and hands it to you. Selling burns the pack, sells the stocks and pays you out. The price is therefore always the value of the underlying, there is nothing to arbitrage, and nobody has to provide liquidity for a pack to be tradable from the moment it is registered. Two pools exist for every pack, against WETH and against USDG. Holders can always call `redeem` on the vault directly and take the underlying stocks out, pro rata, even if a route or the hook is unavailable. Dividends, airdrops and corporate actions land in the vault and flow to holders through that same pro-rata redemption. ## Identity A pack is its ordered stock list. `keccak256(abi.encode(stocks))` is the salt of its CREATE2 address, so the address is knowable before registration and the same list can never be registered twice. Order is part of the identity: Apple-Meta-Nvidia and Nvidia-Meta-Apple are two different packs, both valid. The ticker is the first letter of each stock symbol in order, so both of those spell ANM and AMN respectively, and tickers are allowed to collide. Never treat the ticker as an identifier. The ERC-20 name carries the full composition and the address is the identity. ## Registering a pack 1. `POST /api/price/stocks` with `{ "stocks": ["0x...", "0x..."] }`. You get back `{ prices, deadline, signature }`. 2. Call `PackRegistry.register(stocks, prices, deadline, signature)`. The signature is a short-lived price attestation, valid for 180 seconds, that fixes the quantities so one unit opens at $1.00. Registration is permissionless and costs network gas only. Calling it twice with the same ordered list reverts, which is how you detect that a pack already exists; `PackLens.exists(stocks)` tells you the same thing without spending gas. ## Pairing a launchpad against a pack The pack is an ordinary ERC-20 as far as your launch contracts are concerned, so your factory needs to do only two things. First, accept it as a quote asset when `PackRegistry.isPack(quote)` is true. Pull that from the registry rather than keeping your own allow-list, and any pack registered by anyone works on your launchpad the moment it exists, with no admin step from you or from us. Second, price your opening market cap in it. `GET /api/nav?pack=0x...` gives you the USD value of one pack unit. Most launch factories want that number signed by their own price signer for their own EIP-712 domain, which you do with your own key: the NAV is data, the signature over it is yours. Buying in one transaction is `ETH -> PACK -> TOKEN`: hop one is the pack pool through PackHook, hop two is your own launch pool. Both run inside a single v4 `unlock`. ## Reading state `PackLens` is the read surface. `packInfo(pack)` returns name, symbol, supply, the stock list, unit quantities, live composition, holdings and NAV in USDG. `packs(offset, limit)` pages through every pack. `stocks()` returns the pickable stocks with their routes and enabled flags. `exists(stocks)` returns whether an ordered list is registered, its address and its ticker. Do not price a pack from pool reserves. There are none. Use `PackLens.navUsdg`, or `GET /api/nav`. ## Trading `PackRouter` covers it: `buyWithEth(pack, minOut)` payable, `buyWithUsdg(pack, amountIn, minOut)`, `sellForEth(pack, amountIn, minOut)`, `sellForUsdg(pack, amountIn, minOut)`. Approve the pack to the router before selling. To quote a trade, `eth_call` the same function you are about to send and read the return value; there is no separate quoter, because the router's own execution is the quote. ## SDK `npm i @lnchr/sdk viem` ```ts import { lnchr } from "@lnchr/sdk"; const sdk = lnchr(); const stocks = await sdk.getStocks(); const packs = await sdk.getPacks(); const { registered, pack, ticker } = await sdk.predictPack([stocks[0].address, stocks[1].address]); const register = await sdk.buildRegisterPack([stocks[0].address, stocks[1].address]); const buy = sdk.buildBuyWithEth({ pack, minOut: 0n, value: 10n ** 17n }); ``` Every builder returns `{ address, abi, functionName, args, value }`, ready for `walletClient.writeContract` or wagmi's `useWriteContract`.