---
name: foci
description: Build applications against the foci launchpad on Arc — launching tokens, trading bonding curves, graduated Uniswap V4 pools, fees and referrals. Use when writing code that calls foci contracts, or when debugging a revert from one.
---

# foci

foci is a permissionless bonding-curve launchpad on Arc (arc-testnet, chain 5042002).
Tokens trade on a curve until a fixed amount is raised, then graduate into a Uniswap V4 pool
with permanently locked liquidity.

## Getting the full reference

The complete documentation — every address, function signature, selector, event topic and
error — is one document:

    https://foci.family/llms-full.txt

10 contracts · 202 functions · 70 events · 140 errors.
Fetch it before writing code. Individual pages are available as `https://foci.family/documentation/<page>.md`.

## The five things that are counter-intuitive

Most integration failures are one of these. They are worth knowing before you read anything else.

### 1. The approval target is not the contract you call

| Calling | Approve |
|---|---|
| `factory.launchToken` | the **factory** |
| `launchAndBuy.launchAndBuy` | the **router** |
| `curve.buy` and `curve.sell` | the **curve** (quote asset to buy, memecoin to sell) |
| a pool swap | **Permit2, then the router** — two transactions |

Approving the wrong contract fails with a bare ERC-20 allowance revert that names neither the
expected spender nor the amount.

A pool swap needs `ERC20.approve(token, PERMIT2)` **and**
`permit2.approve(token, router, amount, expiry)`. Skipping the second reverts
`AllowanceExpired` (`0xd81b2f2e`) — a name that suggests a grant lapsed when in fact one
was never made.

### 2. Two decimal scales

The quote asset is **6-decimal** USDC at `0x3600000000000000000000000000000000000000`.
Every memecoin is **18 decimals**. Arc's *native* asset is also called USDC but is 18
decimals — it is a different thing and must not be used as the trade amount.

Never round-trip an amount through a JavaScript number. Use `parseUnits`/`formatUnits` and
keep bigints end to end.

### 3. A buy that crosses the graduation threshold needs an explicit gas limit

The crossing buy tries to seed the Uniswap pool inside the same transaction, wrapped in
`try/catch`. `eth_estimateGas` therefore returns a limit sized for the **seed-fails** path
— which is never enough for the seed to succeed. This is deterministic, not flaky.

Send roughly `estimate + 1_200_000` on any buy that might cross. When it fails anyway the
curve emits `AutoSeedFailed` and the launch sits in phase 1 with **no tradeable venue** until
someone calls `factory.createGraduatedPool(token)` — which is permissionless, so run a keeper.

### 4. The two slippage bounds are different kinds of bound

On `buy`, `minTokensOut` is a **price** bound: an oversized buy is clamped to the remaining
allocation and the remainder refunded, so overshooting is safe. On `sell`, `minQuoteOut` is
a strict **quantity** bound.

`sell` also closes the instant `readyToGraduate()` is true — before the `graduated` flag is
set. Check both, or you will offer a sell button that always reverts.

### 5. Per-launch contracts have no fixed address

`FociV2BondingCurve` and `FociV2LauncherToken` are deployed once per launch. Read them from
`factory.getLaunchedToken(token)`, which returns a **zeroed struct** for an unknown token
rather than reverting — check `.exists` first, or an unknown address looks like a live curve
at phase 0.

## Phases

`0` NotGraduated (curve) · `1` Swept (**no venue**) · `2` PoolCreated (V4 pool) · `3` Rescued.

Branch on `getLaunchedToken(token).phase`. Do not infer the venue from whether a pool exists.

## Quoting

Curve phase: `GET /v1/tokens/:address/quote` on the foci API — note it takes **whole units**,
not base units. Pool phase: the API refuses by design; use Uniswap's V4Quoter, which simulates
through the real hook so the hook fee is included.

## When a transaction reverts

Look the selector up at `https://foci.family/documentation/errors.md` — every custom error across every
contract, by selector. Decoding beats guessing.
