A hooked token is a standard Solana Token-2022 token whose mint carries a transfer hook: one shared engine program that runs a stack of rules — picked by the creator at launch, written into an on-chain config, and Locked there — inside every transfer of that token. Buys, sells, and wallet-to-wallet sends all pass through the same check, and any rule can veto a transfer. Everything else about the token is ordinary: a standard mint, a standard Meteora DBC bonding-curve pool, no proprietary token program. This page is for the person holding one — or thinking about it.
Holder guide · last verified 2026-10-21 · the rule panels are the reference for parameters; each token's preflight report is the reference for that token.
Per-token configurations are Locked — no one can change a launched token's rules. The engine program itself currently retains an upgrade authority held by the platform operator. That is a platform-level trust assumption: a future engine upgrade could change enforcement for all tokens. An independent review of the engine is planned, and the decision to burn the upgrade authority will be made with that review in hand. Until then, AgentOnly does not claim the engine is fully immutable.
The rules are the token. Two tokens from the same launcher can behave completely differently — one is freely tradable, the next vetoes your sell until the price dips under your entry. The decode is published, per token, before you need it:
You can also decode it yourself: the mint's TransferHook extension names the engine program, and the token's config — the ordered rule stack, the authority mode, the venue allowlist, the exemptions — lives in a program-derived account keyed by the mint (["config", mint]) that anyone can read. The preflight report is that read, done for you and dated.
We never collapse these into one "compatible" badge, and you shouldn't let anyone else do it either:
| Question | What it means |
|---|---|
| Route supported | The trade can be built: the mint is standard Token-2022, the pool is a standard venue pool, and the hook's extra accounts resolve through the standard Token-2022 resolver — no custom integration, no proprietary anything. |
| Route tested | A named execution actually ran — a real buy or sell, by a named method, with a signature you can open. The tested rows for each token are on its preflight report. |
| Provider indexed | A named provider (an aggregator, a trading bot) surfaces the token in its index or app. Indexing says nothing by itself about the other two. |
When a bot or app answers "No route" for a hooked token, that is the provider declining — in its own backend, before any transaction is built. It is not the token refusing you, and it is not your wallet failing. We observed exactly this from BasedBot for the launcher's mints (2026-10-20), while the same mints were routing through generic resolvers with mainnet receipts (below). Our assessment is that the refusal happens on the provider's side, in its coverage and claimer handling; the provider has not confirmed a reason, and we label the explanation as our assessment. Price a "No route" as a statement about that provider's coverage — then use a route that is tested.
A launcher token trades on its Meteora DBC bonding curve. Any client that routes DBC and resolves Token-2022 hook accounts through the standard resolver (addExtraAccountMetasForExecute — the function the DBC SDK itself calls) can build the buy. Engine v3 keys each holder's record to their token account's address, a value computable before the account exists, precisely so a first buy for a brand-new wallet resolves with no custom work. That isn't theory: on HARVEST, a fresh wallet whose token account did not exist when the transaction was built bought 0.01 SOL → 748,452.588404 HARVEST through the generic resolver alone (2MtGkjSaEb…FZMXKX).
The doors, honestly labeled:
Gate rules change the buy, not the route. On an Agent-Only or Ecosystem Gate token, an unregistered receiver is vetoed — register and sync first (section 6), then the same buy lands. On a Holder-Gated token, a plain curve buy fails closed by design, because a curve swap cannot carry the gate-balance sync; buy through a surface that syncs first (the trade page, hook.mjs).
Selling runs through the same doors in reverse. One asymmetry matters: a sell is a transfer out of your wallet, so the sender-side rules judge it — above all, the Basis Latch.
When you receive a latch token, the engine writes down your basis — your average entry price — in a holder record tied to your token account. (Buy more and the basis blends, weighted by size; buy cheaper and it ratchets down.) The latch does not compare your basis to the last trade print. It compares it to the token's price feed: a cranked EMA — an exponential moving average, a smoothed reading of the pool price — kept fresh by a crank service and never trusted once it is older than the token's staleness limit (300 seconds on the current tokens). One wild print doesn't arm or disarm anything; the smoothed feed has to actually cross.
While the feed sits at or above your basis, your sells — and your sends — are vetoed with Locked. The first time the feed dips below your basis, you latch. What that buys you depends on the token's mode: in classic mode you are unlocked permanently, at any later price, even a profit. In LIVE mode you stay unlocked only while the feed stays below. In graduated mode there is no single unlock: you earn a sellable fraction over time, dips speed it up, and a sell larger than your earned fraction is vetoed with PartialLocked — the part you've earned always sells.
The receipt: the fresh wallet that bought HARVEST through the generic resolver tried to sell immediately. The transaction 4hNkuskxxt…LpVG6Y failed inside the transfer with engine error Locked, and the buyer's balance was unchanged. The failed transaction is the rule working — if you're holding a latch token, expect your first sell attempt above your entry to look exactly like that.
Escrow Split exists only on house-graduated tokens (today: HPROOF). On a house-venue buy, a fixed share of the SOL you spend — HPROOF: 50% — is held into a personal escrow account keyed to your token account instead of trading; curve buys are never split. When you later sell on the house venue, the escrow resolves in proportion to the share of your position you sold, by the same dip test as the latch:
The numbers (mainnet, HPROOF): a 0.10 SOL house buy escrowed exactly 0.05 SOL. Selling half the position after a dip resolved 24,997,064 lamports and refunded 23,997,181 to the seller (3fiTsVeEnV…w8fAae). A second buyer sold 40% of his position above entry: 11,994,704 lamports resolved and forfeited to depth, refund exactly 0 (2co1wyRfWL…xFHsUi). Resolution never blocks the sell itself — with no escrow record there is simply nothing to resolve.
One state note: holder records are keyed to your token account — your associated token account (ATA) is the canonical one. If you hold the same token across several token accounts, each carries its own record (its own basis, its own latch) until you merge them (node hook.mjs merge). Fragments can only ever be more locked, never less.
A transfer of a hooked token is not just source, destination, and amount. Token-2022 calls the engine inside the transfer, and the engine reads its state from extra accounts the client must attach — the token's config, your holder record, the price feed, and more, depending on the token's rules. Before judging anything, the engine checks the delivered set: if a required account wasn't supplied, the transfer fails closed with MissingExtra (error 26). The config and the instructions sysvar are required for every hooked token, so this isn't only about per-holder rules.
A plain wallet Send builds a bare transfer — it attaches none of those accounts. On a hooked token the send therefore fails even though you hold the tokens, the recipient is fine, and nothing about the token is broken. The token isn't refusing you; your client never handed the engine its state. The fix is a client that resolves the account list — the next paragraph — not a different token and not a retry.
Which rules judge a send at all? The hook runs on every transfer, but each rule only judges the shapes it's about:
| Judged on wallet-to-wallet sends | How |
|---|---|
| Basis Latch (1) | The sender is gated exactly as on a sell: locked until the dip (graduated: only up to the earned fraction). |
| Agent-Only (3) · Ecosystem Gate (17) | The recipient must be registered — for rule 17, attested through the named ecosystem's flow. It's the recipient's record that matters, not the sender's. |
| Holder-Gated (8) | The recipient's gate-token balance is checked at receive time. |
| Max Wallet (9) | The recipient's post-send balance must stay under the cap — a send that would cross it is vetoed outright, never partially filled. |
| Allow/Blocklist (10) | Every receive is judged against the token's lists. |
| Trading Hours (12) | At scope 0, the clock judges every transfer, sends included. At scope 1, only trades keep hours and sends move anytime. |
| Vesting Clock (13) | The sender may only move their unlocked fraction. |
| P2P Toggle (7) | In no-p2p mode the send itself is the thing vetoed — every transfer must be a trade. |
| Not judged on sends | How |
|---|---|
| App-Gated (4) | Venue receives only — a send is not this rule's business. |
| The Grudge (11) | Venue shapes only: sends never mark anyone and are never penalized. |
| Escrow Split (2) | House-venue trades only; sends are untouched and no escrow moves. |
| Crown (5) · Tithe Seat (6) · King of the Pool (15) · Buyback & Burn (16) · Decay Tax (14) | Settlement- and crank-side rules: none of them can veto a transfer. (The King's record updates on transfers, but it observes — it never blocks. Decay Tax is a fee schedule, not a veto — and is not launchable today.) |
The working path. Send through a client that resolves the hook's account list and prepends the syncs the token's rules need. node hook.mjs send <tokens> <wallet> does exactly this: it creates the recipient's token account if they don't have one, settles your outstanding holder-fee state, syncs the recipient's gate balance immediately before the transfer on Holder-Gated tokens, and builds the transfer with the standard resolver-aware builder (createTransferCheckedWithTransferHookInstruction). One thing no client can do for the recipient: on Agent-Only and Ecosystem Gate tokens, the recipient must have registered (and, for rule 17, been attested) and synced for that token first — registration is self-signed by design, so it's their step. If they haven't, your send vetoes with NotRegistered and nothing moves.
What it looks like: the transaction fails — the explorer shows the engine's error name in the program logs — and that's all that happens. Your balances and the token's rule state are exactly as they were before: a veto is atomic, there is no partial fill, no pending state, no tokens in limbo. As with any failed Solana transaction you still pay the (small) network fee. Read a veto as the token's constitution working, not as a broken token.
| Veto | What it means | What you can do |
|---|---|---|
| NotRegistered (1) | The recipient — on a buy, that's you — has no active Registry record mirrored for this token (Agent-Only / Ecosystem Gate). | Register and sync: node hook.mjs register, then node hook.mjs sync (≈0.0012 SOL on the AGTR proof). It's self-signed; nobody can do it for you. |
| WrongEcosystem (24) | You're registered, but not attested through the specific ecosystem this token requires. | Enroll through that ecosystem's own flow (its skill), then sync. |
| Locked (15) | Basis Latch: the feed is at or above your basis and you haven't latched. | Nothing is broken and there's nothing to fix — wait for a dip below your basis. In classic mode the first dip unlocks you permanently. |
| PartialLocked (25) | Graduated latch: the amount exceeds the sellable fraction you've earned so far. | Sell up to your earned fraction now, or wait — time held and dips grow it. |
| StalePrice (16) | The price feed is older than the token's staleness limit. Latch decisions are never made on old prices, so latch tokens fail closed meanwhile. | Wait and retry — the crank service refreshes every feed on a ~30-second poll. |
| BasisMissing (17) · HolderMissing (9) | You hold tokens but have no holder record (or no basis in it) — a record that predates tracking, or one never created. | Receive once through a resolver-aware client, or run node hook.mjs sync — the record is created or repaired; the engine never silently passes instead. |
| MaxWalletExceeded (2) | The receive would push the recipient past the token's per-wallet cap. | Reduce the amount so the recipient's balance stays under the cap. |
| NotGateHolder (19) | The recipient's gate-token balance is below the token's minimum (or hasn't been synced). | Hold at least the minimum of the gate token, and receive through a surface that syncs (the trade page, hook.mjs send). |
| OutsideTradingHours (28) | The transfer is outside the token's configured days/window. | Wait for the window. (Scope-1 tokens: sends still move at any hour.) |
| VestingLocked (29) | The amount exceeds the unlocked fraction of your position. | Move only the unlocked part, or wait for the schedule to release more. |
| GrudgeMarked (27) | You're marked for dumping a large share of your bag inside the window; venue buys are banned (or capped) while the mark lasts. | Selling and sending are unaffected. Wait out the mark — repeat offenses last longer. |
| AppNotAllowed (32) | A venue receive arrived through a program that isn't one of the token's named apps. | Trade through one of the named apps. |
| P2PTransferForbidden (21) · VenueTransferForbidden (20) | The token's P2P Toggle forbids that path entirely (no-p2p / p2p-only). | Use the other path: trade on the venue, or send hand-to-hand. |
| NotAllowlisted (30) · Blocklisted (31) | The token's curated lists refuse the recipient. | Only the token's config authority can add an allowlist entry. A blocklist sealed under a Locked config is permanent — there is no appeal path, by design. |
| MissingExtra (26) | Your client didn't attach the accounts the hook requires — the wallet-Send trap (section 5). | Use a resolver-aware client (hook.mjs, the trade page). This veto is about the tool, not about you. |
Every token picks its ending at launch — it's printed on its preflight report — and the three endings do very different things to a holder:
| Mode | What happens, and what it means for you |
|---|---|
| release | At the curve threshold (HARVEST: 42 SOL), a real DAMM v2 pool is created and the transfer hook is revoked inside the completing swap. The rules end. Your tokens become plain Token-2022 in a normal pool — every wallet, bot, and aggregator treats them like any other token; no holder records, no vetoes, sends always work. If the token pays holder fees, the Distributor keeps paying after graduation — it never depended on the hook. Honest status: no launcher token has completed a live release graduation yet; the path is simulation-proven (46/46), not yet mainnet-executed. |
| never | The migration threshold is set to the maximum the venue accepts (u64 max — more SOL than exists), so the curve never completes. The rules are permanent: the token lives on its curve forever, only hook-aware doors can ever trade it, and the 20% migration share stays locked in the pool. What you read in the preflight is the token's behavior for its entire life. EVER is the live example. |
| house | At the token's engine-side threshold (HPROOF: 0.2 SOL), anyone can activate the house venue — activation is permissionless once the threshold is crossed. The hook is not revoked: the same engine keeps judging every transfer, Escrow Split keeps settling on house trades, and the curve stays open as a legacy door. What changes for you is the default place to trade — your rules don't retire. HPROOF ran this on mainnet on 2026-10-20; its preflight report carries the receipts. |