Docs · Integrations
Routing reel pools: notes for aggregators
What a router such as Jupiter needs to quote and route a reel pool: the curve on tracked reserves, the accounts a swap takes, when a pool refuses, and how recapture and hooked tokens change the picture.
Status
The safest adapter calls the SDK's quoteSwap, which mirrors the program to the atom. Read SDK.
The curve
A reel pool is a full-range constant-product market: rb · eq = k, where eq = reserve_quote + virtual_quote. Three things differ from a plain CPMM:
- Tracked reserves. The curve uses
reserve_baseandreserve_quotefrom thePoolaccount, never the vault balances. Vaults also hold unclaimed LP fees, buckets and the LP stream, and a donation to a vault changes nothing. Quote from the account, not from token balances. - Virtual quote. A launch can open with tokens only, at a chosen price.
virtual_quotedeepens the quote side for pricing but can't be withdrawn, so a sell must satisfygross_quote_out ≤ reserve_quoteor it fails withInsufficientLiquidity. - Charges on top. The base LP fee and each Hook Block charge are computed on the gross quote amount and rounded up; curve outputs round down. A buy's output can also lose its Auto Burn share before it reaches the trader.
State that moves with the clock
Before pricing, the program advances the pool to the current time and slot: it releases the LP stream, steps the dynamic-fee reference, rolls the Storm sample and lapses the managed fee. The Anti-Snipe tax decays with time, and the per-slot buy cap is counted per slot. A quote is only good for the slot it was computed at, so quote at the slot you expect to land in and keep a slippage limit.
Accounts a swap takes
Swap (tag 50) takes the user, the pool, both vaults, the user's two token accounts, both mints, both token programs, VAULT_AUTH, then optional slots. An unused optional slot is filled with the reel program id.
| Slot | Needed when |
|---|---|
launch | Writable during the launch guard (the per-slot buy budget is kept there) |
wallet_counter | Wallet Cap is on and the guard is running |
seller_holder | Exit Clock on a hooked token: the seller's acquisition time |
oracle | Market Guard, or recapture with a Pyth reference |
aux | Recapture with a sibling reel pool as reference |
adv_a, adv_b, adv_c | Agent gate, market-hours fee (the Calendar), Swap Reward Mint |
| referral and ledger slots | The trader has a live referral link; a gap opener is credited |
Hooked base mints. A token launched on reel is Token-2022 with reel-hook as its transfer hook. Every base transfer needs seven more accounts, in this order: reel_hook, extra_metas, mint_guard, reel_program, src_holder, dst_holder, dst_agent, with source and destination following the base transfer's direction. The extra-metas account ["extra-account-metas", mint] lists them for any Token-2022 client. A swap touches many accounts; an address lookup table keeps it within size.
When a pool refuses a swap
| Error | Code | When |
|---|---|---|
BuysPaused | 6017 | Before buy_open_ts: the first 12 s of a new token, or a Buy/Sell Block pause |
SellsLocked | 6018 | Before sell_open_ts |
ExactOutDuringGuard | 6019 | An exact-out buy while the Anti-Snipe guard runs |
BuyCapExceeded | 6020 | The launch's per-slot buy budget is spent |
WalletCapExceeded | 6021 | The buyer passes the Wallet Cap during the guard |
ZapTargetOnly | 6026 | A Zap Relay target pool and the buyer isn't a feeder |
AgentRequired, ScoreTooLow, CpiRefused | 6027–6029 | Agent gate; CPI callers are refused unless the pool allows them |
OracleUnavailable | 6030 | Market Guard's Pyth feed is stale or missing; it refuses sells too |
InsufficientLiquidity | 6013 | A sell would take more quote than the real reserve |
SlippageExceeded | 6012 | Output below the limit, or input above it |
A router should read buy_open_ts, sell_open_ts and the guard end from the pool and skip it while a window is closed, and should drop a Market Guard pool whose feed is stale rather than retry.
Routing through a program
A routed swap reaches reel by CPI, so it is not a top-level instruction. Three things follow:
- King of the Pool only crowns buys signed by an on-curve wallet at the top level. A routed buy can't take the crown.
- Recapture's gap opener is the last on-curve, top-level wallet whose swap widened a gap. A routed swap is never credited as opener.
- Agent gate refuses CPI callers unless the pool's
agent_flagsbit 1 allows them (CpiRefused).
The trader still pays the same fees either way.
Exact-out
Exact-out is computed by inverting every fee at its most (the dynamic fee at its ceiling, Auto Burn inverted, one atom per charge), then running the forward pipeline. The trader can receive a few atoms more than asked and pays no more than the limit. Exact-out buys are refused during the guard, exact-out sells earn no Swap Reward Mint, and an exact-out swap that closes a recapture gap usually reverts. Prefer exact-in.
Recapture changes the split
On a pool with Arb recapture, a swap that moves the price toward the reference (a Pyth feed, a sibling reel pool, or both) by at least the minimum gap pays a charge on the profit of the gap-closing part: by default 75% of it, capped at half the swap's gross amount. The arber keeps the rest. A stale or missing reference skips the charge; it never refuses the swap. To quote it, pass the same reference to quoteSwap as recapRef; without it the quote assumes no recapture and the swap can come in lower. Read Fees and the recapture split.
Hooked tokens on other venues
reel-hook runs on every transfer of a reel-launched token, wherever it trades. During the guard it caps every receiving wallet's balance, reel's vaults and the creator excepted. During a sell lock, and always for a Canonical Venue Token, it refuses transfers to owners that aren't on-curve wallets or VAULT_AUTH, which stops other programs' vaults. A route that sends a reel token through another venue's vault can fail for these reasons. The hook never taxes or redirects tokens.
Events for indexers
Each swap logs a Swap event (id 2) as Program data: <base64>: pool, user, side, mode, amount in and out, LP fee, protocol, other, burn, recapture, the base reserve and the effective quote after the swap. Recaptures log Recaptured (15) and crowns Crowned (13). Read Errors and events.