ArcadeFun

04 — Docs

How ArcadeFun
works

What launching a coin against another coin means, what decides what you can pair with, and where every fee goes.

Contracts

Not deployed yet. ArcadeFun targets Sonic, chain ID 146. The contracts below are written and tested against live Sonic state; when they are deployed their addresses go in this table, each verified on Sonicscan so the code behind the link is the code that runs. Until then, any address presented as one of these is not.

contractaddress
PairLaunchpadnot deployed
FeeVaultnot deployed
QuoteRegistrynot deployed
CompositeQuoteGatenot deployed
UniV3QuoteGate (Uniswap V3)not deployed
UniV3QuoteGate (SpookySwap V3)not deployed
ShadowQuoteGatenot deployed
V2QuoteGatenot deployed
PairZapnot deployed

Buying with S: PairZap

A coin here trades against another coin, so someone holding only S has two trades to make. PairZap makes them as one transaction: an aggregator's route between S and the pair asset (LI.FI's router, fixed at deployment), then the coin's own Uniswap V3 pool. You sign a single minimum that bounds both; if either leg falls short the whole transaction reverts and you keep what you had.

It has no owner and no settings, holds nothing between trades, and keeps no allowance standing. Its swap callback pays only the pool of a swap it started, only while that swap is in flight. It is a convenience, not a gate: the pool is an ordinary Uniswap V3 pool, and anything that can trade one can trade your coin without it. It has not been audited.

The protocol coin

There is no protocol coin yet. When there is, it will be launched through PairLaunchpad like any other coin — same fixed supply, same locked liquidity, same contract code — and its address will be published here first.

Your coin's own contract

Every coin launched here is a PairToken, and every one of them will show 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. Once one instance is 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 one of these was read off Sonic before it was written down (22 September 2026) — the factories through their own interface, the tokens by symbol, name and decimals, the feeds by description, and Uniswap's periphery by asking each contract for its factory().

Uniswap V3 factory (launch venue and measurement; Oku's deployment)0xcb2436774C3e191c85056d248EF4260ce5f27A9D
Uniswap V3 QuoterV2 (prices the trade panel; simulated, never sent)0x5911cB3633e764939edc2d92b7e1ad375Bb57649
Uniswap V3 SwapRouter02 (not used by the protocol; what routers trade the pools with)0xaa52bB8110fE38D0d2d2AF0B85C3A3eE622CA455
Uniswap V3 NonfungiblePositionManager (not used by the protocol; test helpers only)0x743E03cceB4af2efA3CC76838f6E8B50B63F184c
Shadow concentrated factory (measurement only)0xcD2d0637c94fe77C2896BbCBB174cefFb08DE6d7
SpookySwap V3 factory (measurement only)0x3D91B700252e0E3eE7805d12e048a988Ab69C8ad
SpookySwap V2 factory (measurement only)0xEE4bC42157cf65291Ba2FE839AE127e3Cc76f741
DeFive factory (measurement only)0x47524ca6578E172878aBf6fD6f3E1Cd106c551e6
SonicSwap factory (measurement only)0x0569F2A6B281b139bC164851cf86E4a792ca6e81
Equalizer pair factory (measurement only)0xDDD9845Ba0D8f38d3045f804f67A1a8B9A528FcC
wS0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38
USDC.e (its on-chain symbol is plain USDC)0x29219dd400f2Bf60E5a23d13Be72B486D4038894
USDT0x6047828dc181963ba44974801FF68e538dA5eaF9
stS0xE5DA20F15420aD15DE0fa650600aFc998bbE3955
WBTC0x0555E30da8f98308EdB960aa94C0Db47230d2B9c
WETH (measured, not an anchor)0x50c42dEAcD8Fc9773493ED674b675bE577f2634b
Chainlink S/USD0xc76dFb89fF298145b417d221B2c747d84952e01d
Chainlink stS/USD0xdB17996a889706Bd67771dEa59E0Bf9453aF0CE4
Chainlink BTC/USD0x8Bcd59Cb7eEEea8e2Da3080C891609483dae53EF
LI.FI diamond (the one address PairZap and the dev buy may route through)0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE

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 — $5,000 if listed, $10,000 if not.
registry.requiredDepthUsdE8(address quote) returns (uint256)

Launching

launchpad.launch(LaunchConfig cfg) payable returns (address token, address pool)
launchpad.predictToken(address creator, bytes32 salt) returns (address)
launchpad.launchFee() returns (uint256)

LaunchConfig carries, beyond the obvious:

fieldwhat it does
lpFee / tickSpacingthe pool's fee tier, in hundredths of a bip, and the tick spacing the factory fixes for it. Only tiers inside minLpFee..maxLpFee — 0.3% and 1% — and both ticks multiples of the spacing
creatorBpsshare of supply kept back for you, capped at 20%
feeRoute0 keeps your fees, 1 buys the coin back and burns it, 2 pays your holders
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, 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 pool address
feeVault.positionOf(address token) returns (liquidity, owed0, owed1)
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. A Uniswap V3 position only becomes an NFT when Uniswap's position manager wraps it; underneath it is a slot in the pool keyed by (owner, tickLower, tickUpper), and the fee vault minted into that slot directly, paying the pool in its mint callback. The usual "liquidity locked" detectors look for LP tokens or position NFTs 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 with its source published you can check it rather than believe it: no code path in the vault ever calls burn with a non-zero amount. Collecting fees calls burn with exactly zero — which only moves earned fees into the position's tokensOwed — and then collect. There is no withdraw, no emergency exit, and no owner function that adds one. Anyone can read the position with pool.positions(keccak256(abi.encodePacked(feeVault, tickLower, tickUpper))). 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 scripts make the owner 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.