Contracts

Deployed on Unichain mainnet, chain ID 130. Every one of them is verified on Uniscan, so the code below the links is the code that runs.

Not deployed yet. The Unichain deployment has not happened; the addresses are filled in here, and in the site's configuration, when it does. Until then every page of the site says so rather than reading an empty address.

contractaddress
PairLaunchpadnot deployed yet
FeeVaultnot deployed yet
PairLaunchpadV2 (hooked launches)not deployed yet
FeeVaultV2 (hooked launches)not deployed yet
RainbowHook (the fee hook)not deployed yet
QuoteRegistrynot deployed yet
CompositeQuoteGatenot deployed yet
UniV3QuoteGatenot deployed yet
Slipstream gate (Velodrome)not deployed yet
SampledV4QuoteGatenot deployed yet
V2QuoteGatenot deployed yet

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 was 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

Uniswap v4 PoolManager0x1F98400000000000000000000000000000000004
Uniswap v4 StateView (reads only)0x86e8631A016F9068C3f085fAF484Ee3F5fDee8f2
Uniswap v4 Quoter0x333E3C607B141b18fF6de9f258db6e77fE7491E0
Uniswap Universal Router0xEf740bf23aCaE26f6492B10de645D6B98dC8Eaf3
Permit20x000000000022D473030F116dDEE9F6B43aC78BA3
Uniswap V3 factory (measurement only)0x1F98400000000000000000000000000000000003
Uniswap V2 factory (measurement only)0x1F98400000000000000000000000000000000002
Velodrome Slipstream factory (measurement only)0x04625B046C69577EfC40e6c0Bb83CDBAfab5a55F
Velodrome V2 factory (measurement only)0x31832f2a97Fd20664D76Cc421207669b55CE4BC0
Chainlink ETH/USD (18 decimals)0xBcE70e194940a157f3A80566505a7E96f5238CCa
Chainlink BTC/USD (18 decimals)0xC13f3E310Dd7436FA24338174acB64254b9A8039
Chainlink USDC/USD (18 decimals)0xbd1cD1518eFB92a92100da62D4C488c810dFd75b
KyberSwap router (dev buy and trade panel)0x6131B5fae19EA4f9D964eAc0408E4408b66337b5

Unichain's Chainlink USD feeds report 18 decimals, not the usual 8. Everything that reads them asks decimals() rather than assuming.

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 — $10,000 if listed, $25,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) or getPool(a, b, fee). 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 or for Uniswap V3 and Slipstream: 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:

fieldwhat it does
creatorBpsshare of supply kept back for you, capped at 20%
feeRoute0 keeps your fees, 1 buys the coin back and burns it, 2 gives them to your holders (final; needs a distributor)
feeRecipientzero means the launching wallet
devBuyQuotepair-asset amount spent buying your own coin as the pool's first trade; needs an approval to the launchpad first
devBuyMinOutleast 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 or the rewards pot, the sink
// and the treasury, or the burn.
feeVault.collect(address token)

// Creator only. Both take effect from the next collect. HolderRewards (2) is final.
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
feeVault.buybackSink() returns (address)                       // where the protocol's share goes

// FeeVaultV2 (hooked launches) only — all in the pair asset
feeVault.pendingFees(address token) returns (uint256)          // charged by the hook, not yet collected
feeVault.totalFees(address token) returns (uint256)            // everything charged since launch
feeVault.feeRateOf(address token) returns (uint24)             // the launch's rate, hundredths of a bip

The fee hook

Launches since the hook open a pool with no Uniswap LP fee and RainbowHook as its hook. The hook charges the launch's rate on the pair-asset leg of every swap — the pair asset a buyer pays in, or a seller receives — and never on the coin:

swapthe pair asset isthe hook takes
buy, exact inputthe amount paid inin × rate, before the swap
buy, exact outputwhat the pool chargesin × rate / (1 − rate) on top, after the swap
sell, exact inputwhat the pool pays outout × rate out of it, after the swap
sell, exact outputthe amount asked forout × rate / (1 − rate) extra from the pool, before the swap

Each row is the same rate of the gross pair-asset amount. The fee is minted to FeeVaultV2 as a Uniswap v4 claim (ERC-6909) inside the swap — no token moves mid-swap, so no token can block trading — and collect turns it into the pair asset and splits it. Only the launchpad can open a pool on the hook, the rate is written once when it does, and there is no function that changes it or sends a fee anywhere but the vault. The vault's own buyback swaps are the one thing the hook does not charge.

Routers that go straight to Uniswap v4 (the Universal Router, Uniswap's quoter) handle hooked pools natively; an aggregator has to integrate a hook before it routes through it, so the site trades these coins through the Universal Router itself.

Holder rewards

feeVault.holderRewardsDistributor() returns (address)   // zero until set; route 2 is refused while it is
feeVault.rewardsPot(address token) returns (uint256)    // pair asset waiting for the coin's holders
feeVault.pendingRewards(address token) returns (uint256) // coins the price cap left unsold
feeVault.pendingBuyback(address token) returns (uint256) // pair asset the price cap left unspent

// Distributor only. Lengths must match; the total may not exceed the pot.
feeVault.payHolderRewards(address token, address[] recipients, uint256[] amounts)

event HolderRewardsAdded(address indexed token, uint256 coinSold, uint256 soldFor, uint256 added, uint256 pot);
event HolderRewardsPaid(address indexed token, address indexed quote, address[] recipients, uint256[] amounts, uint256 total, uint256 pot);

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 now that its source is published 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 holder-rewards distributor (replace it, never remove it), 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.

Today the owner is a single EOA. It should be a multisig behind a timelock, and the contracts do not enforce that themselves.

None of this has been audited.