Contracts
Deployed on Arbitrum One, chain ID 42161, on 2026-09-10 at block 503738330. Verification
on Arbiscan follows as soon as an explorer key is on hand (contracts/verify.sh); until then the
source in contracts/src is the contract, and the bytecode on chain is what forge build produces
from it.
| contract | what it does | address |
|---|---|---|
PairLaunchpad | the one-transaction launch: deploy, open the pool, seed it, record it | 0xaf1Fba97FF4F572c85Cc839a10C8f07317c127F8 |
FeeVault | owns every position forever; collects and splits fees creator / buyback | 0xF77613E904c15bEc41fE60c3Af01087Ed4115903 |
QuoteRegistry | eligibility decisions, with manual overrides on top of the gates | 0x9d47734706Ab5FfC1E4Fe4290d8A5B65418419e6 |
CompositeQuoteGate | asks every venue and takes the best answer | 0x67BB97C4c77d0Fa574359343532A3B4917DaE0e7 |
UniV3QuoteGate (Uniswap V3) | depth from Uniswap V3's own oracle, every fee tier | 0x6E90A31B89bFF6598cAe88e1F77Bd40F5AF0Ebe8 |
CamelotQuoteGate | depth from Camelot's Algebra pools, through getTimepoints | 0xE65557CFA7015DA2971B6200414A26DF5E68231D |
UniV3QuoteGate (PancakeSwap V3) | the same contract pointed at Pancake's factory and tiers | 0xa0e92e7FfccC7810fC4523b8d5a26643835Eb50a |
UniV3QuoteGate (SushiSwap V3) | the same contract pointed at Sushi's factory | 0xB1500eE9A014B2CFB702B3E004e73D3F5e82087F |
SampledV4QuoteGate | Uniswap v4 pools, walked tick by tick | 0x29FD1598cF9207F65A167aE5e7c433FEbFd02361 |
V2QuoteGate | Uniswap V2, SushiSwap V2 and Camelot's classic pairs, from reserves | 0x058cDd3D245dfE4f19cE864122AD9134d4BEa52a |
PairBuyback | where the protocol's share goes once $PAIR exists — written, tested, not deployed | — |
Your coin's own contract
Every coin launched here is a PairToken, and every one of them shows as verified without anyone
submitting it. That is not a courtesy — PairToken takes no constructor arguments (it calls back
into the launchpad for its name, symbol and supply), so the creation bytecode is byte-identical
every time. One instance gets verified; the explorer matches all the others, including coins that
do not exist yet.
What that verified source says, and what it therefore cannot do: fixed supply set once in the constructor, no mint function, no transfer tax, no blacklist, no pause, no owner.
External contracts it uses
Every address below was read back on Arbitrum One before being written down.
| Uniswap v4 PoolManager | 0x360E68faCcca8cA495c1B759Fd9EEe466db9FB32 |
| Uniswap v4 StateView (the interface reads through it) | 0x76Fd297e2D437cd7f76d50F01AfE6160f86e9990 |
| Uniswap v4 Quoter (the interface prices through it) | 0x3972C00f7ed4885e145823eb7C655375d275A1C5 |
| Uniswap V3 factory (measurement only) | 0x1F98431c8aD98523631AE4a59f267346ea31F984 |
| Camelot AMM v3 (Algebra) factory (measurement only) | 0x1a3c9B1d2F0529D97f2afC5136Cc23e58f1FD35B |
| PancakeSwap V3 factory (measurement only) | 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865 |
| SushiSwap V3 factory (measurement only) | 0x1af415a1EbA07a4986a52B6f2e7dE7003D82231e |
| Uniswap V2 factory (measurement only) | 0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9 |
| SushiSwap V2 factory (measurement only) | 0xc35DADB65012eC5796536bD9864eD8773aBc74C4 |
| Camelot classic-pair factory (measurement only) | 0x6EcCab422D763aC031210895C81787E87B43A652 |
| Chainlink ETH/USD | 0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612 |
| Chainlink BTC/USD | 0x6ce185860a4963106506C203335A2910413708e9 |
The anchors — the assets every depth reading is priced through — are WETH, native USDC, USD₮0, WBTC and the bridged USDC.e. Five rather than three, because Arbitrum's dollar liquidity is split between three dollar tokens and reading only one would call a real market thin.
Calls worth knowing
Before launching
// Non-reverting. Returns whether it would be allowed, and why not if not.
registry.status(address quote)
returns (bool eligible, Decision decision, Report report)
// The bar this particular asset has to clear — $15,000 if listed, $50,000 if not.
registry.requiredDepthUsdE8(address quote) returns (uint256)
Naming a v4 pool
Every other venue can be searched: a factory answers getPair(a, b), getPool(a, b, fee) or
poolByPair(a, b). Uniswap v4's singleton cannot — a pool is identified by the hash of its key,
and the key contains a 160-bit hook address, so it can be verified but never enumerated. A v4 pool
therefore has to be named once before the gate can see it. Anyone may do it, once, for everyone.
v4Gate.registerPool(PoolKey key) returns (address token)
v4Gate.registerLaunch(address token) returns (address) // for a coin launched here
v4Gate.probe(PoolKey key) returns (uint256 usdE8, address anchor) // read-only, changes nothing
Nothing equivalent is needed for the V2-shaped venues, for the V3-shaped ones or for Camelot: those are searched directly, so a coin with a market there is usable the moment its address is pasted in.
Launching
launchpad.launch(LaunchConfig cfg) payable returns (address token, bytes32 poolId)
launchpad.predictToken(address creator, bytes32 salt) returns (address)
launchpad.launchFee() returns (uint256)
LaunchConfig carries, beyond the obvious:
| field | what it does |
|---|---|
creatorBps | share of supply kept back for you, capped at 20% |
feeRoute | 0 keeps your fees, 1 buys the coin back and burns it |
feeRecipient | zero means the launching wallet |
devBuyQuote | pair-asset amount spent buying your own coin as the pool's first trade; needs an approval to the launchpad first |
devBuyMinOut | least you will accept from that buy — nobody can front-run it, so this guards against you and the pool disagreeing on the opening price |
After launching
// Anyone can call. Proceeds only ever reach the recorded recipient, the sink and the treasury.
feeVault.collect(address token)
// Creator only. Both take effect from the next collect.
feeVault.setFeeRoute(address token, FeeRoute route)
feeVault.setFeeRecipient(address token, address recipient)
// Reads
launchpad.launchOf(address token) // a public mapping: an unnamed tuple
feeVault.launchOf(address token) returns (Launch) // includes the PoolKey
feeVault.feeRouteOf(address token) returns (FeeRoute)
feeVault.feeRecipientOf(address token) returns (address)
feeVault.owed(address token, address who) returns (uint256) // a payout that could not be pushed
feeVault.claim(address token) // collect one
Where the liquidity lock actually lives
There is no lock contract and no locked LP token, because Uniswap v4 has no LP tokens at all — a
position is a storage slot keyed by (owner, tickLower, tickUpper, salt). The usual "liquidity
locked" detectors look for LP tokens sent to a burn address or a locker, and here there is nothing
of the sort for them to find.
What holds instead is a property of FeeVault, and its source is published so you can check it
rather than believe it: no code path in the vault ever passes a negative liquidityDelta.
Collecting fees calls modifyLiquidity with a delta of exactly zero. There is no withdraw, no
emergency exit, and no owner function that adds one. The float cannot come back out — not by the
creator, not by us.
Owner powers
The owner can retune the depth bars, the fee bounds, the launch fee, the treasury, the buyback sink, the curated list, the gates and their parameters. It cannot touch a launch's liquidity, change an existing launch's creator share, or redirect a creator's fees.
Ownership transfer is two-step everywhere: a handover that is never accepted leaves the current owner in place rather than sending the protocol to a wrong address.
The deploy script hands ownership to whatever OWNER names. It should be a multisig behind a
timelock, and the contracts do not enforce that themselves.
None of this has been audited.