The Hook Launcher deploys Solana tokens whose behavior is a stack of on-chain rules, picked at launch and enforced on every transfer — buys, sells, and wallet-to-wallet sends alike. You choose the rules and their numbers in a launch spec; one shared engine program then checks every transfer against that token's stack, and any rule can veto the whole transfer. Tokens are born on a Meteora DBC bonding curve, and an optional distributor pays the curve's fees out to holders.
This page is the human-readable companion to the landing page and the machine-readable agent skill. Same facts, plainer words.
Every rule in the catalog that can live in the engine is live in the engine today: Basis Latch, Agent-Only, App-Gated, P2P Toggle, Holder-Gated, Max Wallet, Allow/Blocklist, The Grudge, Trading Hours, Vesting Clock, and Ecosystem Gate all enforce inside the transfer hook. A token stacks up to eight, in order; the first veto ends the transfer. Every rule now gets a panel below — what it is in plain terms, its parameters with ranges and defaults, how it enforces, one worked example with concrete numbers, when to reach for it, and honestly how far it has been verified.
The settlement rules are also live (deployed 2026-10-20): Crown Beneficiary (5), Tithe Seat (6) and the King of the Pool stream (15) pay out of the Distributor at settlement time, read live from the token's config; Decay Tax (14) runs a mint-wide fee schedule on the FeeSchedule program (program live; the rule itself is not launchable via the standard launcher yet — it needs a fee-extension mint, which the DBC launch path cannot create, and a direct fee-extension mint path is pending); Buyback & Burn (16) is crank-operated. Their panels below carry the full parameters and caveats (split legs on hooked mints, fee-extension mints for rule 14, the rule-16 / holder-fee stream conflict). The last catalog rule to open, Escrow Split (2), went live with the house venue on 2026-10-20: it is venue-side by design — a transfer hook cannot skim a swap — and the HouseSwap program is deployed on mainnet, so rule 2 and graduation house are open. All 17 catalog rules are now live in the engine and its companion programs — with the distinction stated plainly: Basis Latch (1), Escrow Split (2), Agent-Only (3) and Max Wallet (9) have been carried by a live token; the other thirteen are so far proven in trials, and each panel below says which.
Ecosystem Gate (rule 17) admits only wallets attested through a named ecosystem's own flow (a registry tag that lands only when both the wallet and that ecosystem's attester sign). It isn't carried by a launch token yet; its panel is below, and its full treatment is in the agent skill and its spec. Of the sixteen ecosystem presets, only Muse (preset 1) has its attester configured today — presets 2–16 are unset, so no other ecosystem can attest a wallet yet.
When you buy, the engine writes down your average entry price — your basis. While the token's price is at or above your basis, your transfers out are vetoed: you cannot sell into strength. The first time the price dips below your basis, a latch flips and you are unlocked — permanently in LATCH mode, or only while the price stays below in LIVE mode. Basis blends on buys and ratchets down on rebuys.
Example: You buy at a basis of 0.0020 SOL per token. Price rises to 0.0026 → your sell is vetoed. Price dips to 0.0018 → that dip latches you: from then on you can sell at any price, even 0.0030 (LATCH mode; LIVE mode re-locks on recovery).
Use it when… you want a token holders can't dump into strength — exits unlock only after a dip under the holder's own entry, so the first exit is always at a loss (the TaxHarvest mechanic).
Graduated mode: this rule also ships in a graduated form — a sellable fraction earned by time held and accelerated by dips, with the same latch paying 100% at the crossing. It is live on mainnet on the LATCH token. Explained with charts on its own page: The Graduated Latch →
Verification status: Proven end-to-end on the real DBC program in simulation (55/55 latch-on-curve trial) and in the engine suite (64/64). The graduated mode is carried by a mainnet launcher token — LATCH (CFG9xRhq7NJ3UGR7VBU4bBgJotXTMZ2inhcfugX78t27), Locked config, launched 2026-10-16. Its design ancestor, TaxHarvest TH, is live-proven on Solana mainnet.
Classic mode, live on Engine v3: the binary form of this rule — no ramp, no fraction — is carried by HARVEST (2a8hxHj6CFLvQrhjEEDXBhSuRQkLfUMzTW36NijZ1tAo), Locked config, launched 2026-10-16 as the first v3-native token, with a 5% max-wallet cap. Its launch doubled as the v3 public proof: a fresh wallet's first buy built exclusively through the generic resolver landed, and the buyer's immediate sell was vetoed by the latch (engine Locked). Explained with the receipts on its own page: Harvest — the classic latch →
On every buy through the token's house venue, a fixed share of the SOL you spend is held back into a personal escrow account instead of trading. When you later sell through the house venue, that sell resolves a pro-rata share of your escrow by rule 1's dip test: sell into a dip below your entry and most of it comes back to you as a refund; sell above your entry and the resolved share is forfeited into the pool's depth, where it deepens liquidity for everyone else. It is the TaxHarvest escrow idea — half your buy rides along as a fidelity bond on your own exit.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| splitBps | Share of each house-venue buy held into the buyer's escrow | 1–10000 bps | 5000 (50%) |
Enforcement. This rule does not live in the transfer hook at all — a hook can only veto, it cannot skim a swap — so the engine's Execute is a deliberate no-op for rule 2 and the HouseSwap venue program (8aeCfKabRfbXrLY68CXbsgp3x7mgikjwgMF3d7oY1Y8h) does the work, reading splitBps from the token's config at swap time. Only house-venue trades are touched: curve trades — before activation, and on the legacy curve door after it — are never split, escrow resolves only on house-venue sells, and wallet-to-wallet sends are untouched. On a buy, the split is carved from the total quote in first (the swap fee comes out of what remains) and lands as native SOL in an escrow account keyed to your token account. On a sell, the resolved share is your escrow × the fraction of your pre-sell balance you are selling. A dip — your latch has flipped, or the cranked price feed's EMA sits below your recorded basis, with the feed inside its staleness window — pays 96% back to you, 2% to pool depth, 2% to the pool's fee destination (the remainder, rounding included, goes to the fee destination; if the client doesn't pass that wallet, its share folds into depth instead of failing). No dip — or a feed or holder record the venue cannot read, or one gone stale — forfeits the whole resolved share to depth. Resolution never bricks the sell itself: with no escrow record there is simply nothing to resolve.
Composition. Two hard requirements, both rejected before launch if missing: graduation must be house (a curve token has no venue to split in — the launcher's spec check throws, and the engine separately refuses a rule-2 config with no house commitment block), and rule 1 (Basis Latch) must be enabled alongside, because resolution reads the price feed and the seller's basis/latch state that only rule 1 maintains. The proven pairing runs rule 1 in GRADUATED mode: in classic LATCH mode the latch vetoes an above-entry sell outright, so the venue never gets to resolve that sell's escrow.
Example (mainnet, HPROOF): at splitBps 5000, a 0.10 SOL house buy escrowed exactly 0.05 SOL. The buyer later sold half his position into a dip: 24,997,064 lamports resolved, 23,997,181 (96%) refunded to his wallet. A second buyer sold 40% of his position above entry: 11,994,704 lamports resolved and forfeited to pool depth in full — he received only his swap proceeds.
Use it when… you want the house-venue version of TaxHarvest economics: buyers post a bond with every buy, dip exits are rebated, and strength exits subsidize the pool's depth.
Verification status: Mainnet-proven on HPROOF (5hXj8x3UCx4VqxpoyrNQTbfQxp4MAqjzTj3xqbJDSZEn; stack [1 Graduated Latch, 2 Escrow Split 5000 bps, 9 Max Wallet], Locked, house threshold 0.2 SOL) — both resolution branches reconciled to the lamport, 2026-10-20. In simulation: the HouseSwap trial suite passes 87/87 and the launcher's house suite 37/37.
Only wallets with an active record in the Registry may receive the token — buys and sends alike. The Registry is the guest list: a wallet puts itself on it with one signed registration transaction, and a per-token sync mirrors that record where the hook can read it.
Example: On mainnet, an unregistered wallet's AGTR buy reverted with NotRegistered and it received 0; after registering (≈0.0012 SOL) and syncing, the same buy landed.
Use it when… the token is members-only — the guest list is the Registry, and registration is one signed transaction.
Verification status: Mainnet-proven on AGTR: a registered wallet's buy passed; an unregistered wallet's identical buy was vetoed and received 0.
Venue trades may only arrive through named apps. When a transfer lands in venue context — a trade — the hook looks at which program is actually executing the transaction, and the receive passes only if that program is one of the apps named at launch. Buy the same token through the raw curve, a different app, or any other door, and the receive is vetoed. It is the app-exclusive genre: the token trades inside the apps that distribute it, nowhere else.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| apps (or app1 / app2) | The program ids allowed to deliver venue receives | 1–2 program ids, none of them the zero key | None — at least one app is required |
Enforcement. Only venue-context receives are judged — the rule reads the executing top-level program of the transaction and compares it to the list. A match passes; anything else is vetoed with AppNotAllowed (error 32) and the whole transaction fails. Wallet-to-wallet sends are not this rule's business at all (rule 7 governs them), sells pass because the receiving account is the pool itself, which is exempt by launch config, and exempt destinations always pass. Two consequences worth knowing before you launch: a plain curve trade names the DBC program as the caller, so curve trades pass only if you list the DBC program itself as an app; and each named app must also sit in the token's venue allowlist, or caller validation rejects the trade before this rule is even consulted. An empty app list is rejected at config write — a gate with no apps on it would be a config that lies.
Graduation. The rule lives in the token's config like every hook rule: under release it retires when the hook is revoked at migration; under never it judges venue trades forever; under house the hook stays, so the gate keeps applying on the house venue too.
Example: A token names one game app. A buy routed through that app lands; the identical buy sent straight to the curve program is vetoed with AppNotAllowed; sending tokens to a friend's wallet is unaffected either way.
Use it when… distribution is the product — the token should only change hands inside the app(s) that give it meaning, the way app-native game or social tokens do.
Verification status: Trial-proven, not yet carried by a mainnet launch. The engine's v4 trial suite (73/73) drives it end-to-end: an allowlisted app receive passes, a non-app venue receive vetoes with error 32, a curve-venue receive vetoes, and sells and wallet-to-wallet sends pass.
A fixed share of every fee settlement is carved out and paid to whoever currently holds the token's crown — a per-token beneficiary seat recorded in the Crown program that can be challenged for and won. The token, its pool, and its rules never change; only who gets paid does. The seat is a stake-vote contest: anyone can bond SOL to challenge for it, stakers back either side, and if the challenger out-stakes the reigning side past a quorum, the seat flips at finalize and the stream follows the new holder from the next settlement on.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| crownBps | Share of each Distributor settlement paid to the crown's current beneficiary | 1–10000 bps | 500 (5%) |
Enforcement. There is no transfer-time behavior — the engine's Execute is a no-op for this rule. The rule is read at settlement time by the token's Distributor (DistributeWithSplits): after the crank caller's cut, the crown leg takes crownBps of the net fold (floor math) and pays it live to the beneficiary recorded in the token's Crown PDA (HWZpJ7GnDifwo7g77PKefeVXdzbse7sfRjKrNUna3gJN) at that moment. The leg fails open: if the crown record is missing or malformed, or the recipient account doesn't check out, the leg is skipped and its share folds into the holder index instead — a settlement never bricks over a crown. (One hard edge, shared by all three split rules: if the hook itself vetoes a leg's payout transfer, the whole settlement instruction reverts atomically and can simply be retried — clients pre-check recipients and skip legs they know will veto.) The crown itself is set up per token by a one-time Crown Init — any signer can send it, naming the first beneficiary and a treasury — and contested through its challenge game: bond, 72-hour voting window, 24-hour timelock, a 7-day minimum reign and 3-day cooldown between challenges, and a 20% slash on the losing side's stake, split half to the treasury and half pro-rata to winning stakers. Those are the Crown program's stored defaults (bond 0.1 SOL, quorum 0.5 SOL total stake); an Init can override each of them. Until a token's Init is sent, the token has no crown record and the leg simply skips.
Composition. The three settlement carves share one pot: at config write the engine rejects any stack whose crownBps + Tithe Seat titheBps + King of the Pool titheBps sum to more than 10000 bps. The rule also only ever pays out if the token actually has settlements — a token launched without holder fees has no Distributor and no folds, so the carve never fires.
Example: At the default 500 bps, a settlement folding 2 SOL of claimed fees pays 0.1 SOL to the current crown beneficiary and folds the remaining 1.9 SOL (less the caller's cut) to holders. If a challenger wins the seat the following week, the next settlement's 5% goes to the challenger — nothing about the token changed.
Use it when… you want a contestable revenue seat on the token — a beneficiary position the market can bid for with stake, instead of a hardcoded fee wallet.
Verification status: Trial-proven; no mainnet receipt yet. The Crown program is deployed on mainnet (2026-10-20) and its trial suite passes 66/66 with every lamport exact; the Distributor's split trials pass 42/42 and the engine's config-write validation for the settlement rules 46/46. No token's Crown Init has been sent, so no live crown exists yet.
A fixed share of every fee settlement is paid to whoever currently holds one specific NFT — the seat. The seat is named at launch by its mint; from then on the revenue stream belongs to the NFT, not to any wallet: sell the NFT and the stream moves with it, automatically, from the next settlement on. It turns a fee share into a tradable asset with its own market.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| seatMint | The NFT mint whose current holder receives the tithe | Any mint except the zero key | None — required |
| titheBps | Share of each Distributor settlement paid to the seat holder | 1–10000 bps | 300 (3%) |
Enforcement. Like rule 5, this rule never touches a transfer — the engine's Execute is a no-op for it. At settlement time the Distributor's DistributeWithSplits reads titheBps live from the token's config (after the caller's cut, and after the crown leg when both are present) and pays that share of the net fold to the current owner of the seat token account — an account of the seat mint holding exactly 1 token. The leg fails open: if the seat account is missing, doesn't hold exactly 1, or the recipient account doesn't match the seat's owner, the leg is skipped and its share folds into the holder index. The seat itself is just an NFT — this system mints nothing and custodies nothing; whoever holds it at settlement time gets paid.
Composition. The settlement carves share one pot: at config write the engine rejects any stack whose Crown crownBps + titheBps + King of the Pool titheBps sum to more than 10000 bps. And as with rule 5, the tithe only pays when the token has settlements — no Distributor (holder fees off), no folds, no tithe.
Example: At the default 300 bps, a settlement folding 2 SOL pays 0.06 SOL to the seat NFT's holder. The holder lists the NFT that evening; whoever buys it receives the 3% at every settlement after the sale, for as long as they hold it.
Use it when… a fee share should be ownable and sellable as an asset — a creator seat, a community treasury seat, or a prize — instead of being wired to one wallet forever.
Verification status: Trial-proven; no mainnet receipt yet. The Distributor's split trials (42/42) pay the seat leg to the seat mint's current holder and skip it cleanly when the seat record is absent or wrong, and the engine's settlement-rule config validation passes 46/46. No mainnet token carries rule 6 yet.
This rule constrains where the token may move. In no-p2p mode, wallet-to-wallet sends are vetoed and every transfer has to be a trade on the venue. In p2p-only mode, venue transfers are vetoed and the token moves hand to hand only — the curve can be seeded but not bought from.
Example: no-p2p: sending 1,000 tokens to a friend's wallet is vetoed; selling the same 1,000 on the curve passes.
Use it when… you want to force all movement through the market (no-p2p — no side deals, every transfer is a trade), or the mirror image: a pure hand-to-hand social token that never trades on its curve (p2p-only).
Verification status: Covered by the engine suite (64/64) and the DBC-binary integration trials (40/40); not yet individually mainnet-proven.
Receiving this token requires already holding at least a set amount of a different, named token — the gate token — checked at transfer time. If the receiver's gate balance is below the minimum, the receive is vetoed.
Example: Gate = a named token, minimum 1,000: a wallet holding 999 cannot receive; at 1,000 it can. In v1, curve buys fail closed (the curve can't carry the gate sync) — distribution runs through surfaces that sync first, like the skill's send.
Use it when… receiving should require skin in another game — only holders of your first token can receive the sequel.
Verification status: Covered by the engine suite and DBC-binary trials; fails closed on curve buys in v1 by design; not yet individually mainnet-proven.
No wallet may receive past a cap share of total supply, set in basis points and checked at receive time. A transfer that would push the receiver over the cap is vetoed outright — it is not partially filled. (The pool and distributor accounts are exempt by launch config, so the curve itself never self-blocks.)
Example: Cap 500 bps on a 1B supply → no wallet may receive past 50,000,000 tokens; a buy that would cross the cap is vetoed outright, not partially filled.
Use it when… you want anti-whale fairness — no single wallet can corner more than a set slice of supply at receive time.
Verification status: Live in AGTR's stack on mainnet at 500 bps; the cap veto itself is proven in the engine suite and DBC trials.
Two curated lists, enforced at receive time. The blocklist names wallets that may never receive the token. The allowlist inverts it: only pre-approved token accounts may receive at all. Either list can run alone, or both together — the blocklist checked first, then the allowlist. The lists are not launch parameters: they live in their own per-token accounts and are written by the token's config authority after launch, so curation is an operational act, not a relaunch.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| mode | Which lists run: blocklist, allowlist, or both | One of the three | both |
Enforcement. Every receive is judged, venue trades and wallet-to-wallet sends alike (exempt accounts — the pool, fee vaults — skip both legs). The blocklist leg matches on the destination owner: if the owner is on the sealed list, the transfer is vetoed with Blocklisted (error 31); no list written yet reads as an empty list. The allowlist leg matches on the destination token account and fails closed: no entry, or an entry switched off, vetoes with NotAllowlisted (error 30). The blocklist holds at most 36 owners. Who writes what matters: the blocklist is written by the config authority, and under a Locked config the first write seals it — a second write fails, forever (under Creator/Agent modes the authority may replace it; HolderVote configs reject direct writes). Allowlist entries are different on purpose: the config authority can add, activate, and revoke them under every authority mode, Locked included — a Locked token with an unmaintainable allowlist would be a brick. An entry can even be written for a token account that doesn't exist yet, pre-approving a wallet's account before its first receive.
Graduation. As a hook rule it retires with the hook under release, and keeps judging every receive forever under never or house — with the blocklist's seal, where it applies, surviving every mode.
Example: A token launches in blocklist mode; before announcing, the creator seals the list with one known drainer wallet on it. That wallet's buys and incoming sends now veto with Blocklisted — and because the config is Locked, nobody, the creator included, can ever take it off.
Use it when… the token needs an explicit gate at the wallet level: a denylist for known-bad wallets, an allowlist for a genuinely private distribution, or both.
Verification status: Trial-proven; no mainnet launch carries it yet. The engine's v4 trial suite (73/73) covers both legs: blocklist write → veto 31 → replace under Creator mode → Locked second write rejected → stranger write rejected; allowlist missing entry → veto 30 → activate → pass → revoke → veto 30 again, with entries manageable under a Locked config.
The token remembers who dumped it. If a wallet sells more than a set fraction of its bag inside a set window, it is marked — and while the mark lasts, its venue buys are banned outright, or capped to a trickle. Repeat offenses stretch the mark: the second lasts twice as long, the third three times, up to a cap you set. Selling is never blocked; the grudge prices your return.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| dumpThresholdBps | Fraction of the tracked bag whose sale inside the window triggers a mark | 1–10000 bps | 5000 (50%) |
| windowSecs | The rolling window sales are measured over (0 selects the engine default) | Any duration | 86400 (24 h) |
| penaltyDurationSecs | Base mark duration; offense n lasts this × min(n, maxEscalation) | Any duration | 86400 (24 h) |
| penaltyMode | ban — marked wallets cannot buy on the venue; cap — marked buys are capped per trade | ban or cap | ban |
| buyCapAmount | Max tokens per single venue buy while marked (raw token units) | Required when penaltyMode is cap | — |
| maxEscalation | Cap on the duration multiplier (0 selects the engine default) | 0–255 | 4 |
Enforcement. Only two transfer shapes matter, and both are venue-shaped. A sell — a transfer from a normal wallet into the venue — feeds the tracker: the window's bag is your balance at the window's first sale, sales accumulate inside the window, and crossing the threshold marks you and resets the window, so a marked wallet that offends again starts from a clean slate and a longer mark. A venue buy — a transfer out of the venue to a normal wallet — is where the mark bites: ban vetoes it with GrudgeMarked (error 27); cap vetoes any single buy over buyCapAmount with the same error. Wallet-to-wallet sends are never sales and never buys here — they don't mark and are never penalized. Config writes reject a zero threshold, and cap mode without a cap amount: a grudge that can never trigger, or a cap with no number, is a config that lies.
Example: Defaults throughout. You hold 10,000 tokens and sell 3,000, then 2,500 more within the day — 5,500 sold against a 10,000 bag crosses the 50% threshold: marked for 24 hours, venue buys vetoed. Do it again after the mark lapses and the second mark lasts 48 hours; the fourth and later offenses cap out at 4 days.
Use it when… you want dumping to have a memory — exit is always free, but a wallet that dumps its bag can't quietly buy the dip back at full size five minutes later.
Verification status: Trial-proven; no mainnet launch carries it yet. The engine's v4 trial suite (73/73) pins the arithmetic: window tracking, the threshold crossing, escalating durations, and both penalty modes vetoing with error 27.
The token keeps office hours. Transfers are allowed only inside one daily window on chosen weekdays, in one fixed timezone — outside the window, the hook vetoes with OutsideTradingHours. It is the market-hours token: it trades while its market is open and simply refuses to move the rest of the time. The honest limitation is in the design, not hidden: the offset is a fixed number of seconds, and a fixed offset cannot follow daylight saving. A New York token is configured for EST or for EDT and re-issued at the change, or it accepts a seasonal one-hour shift.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| tzOffsetSecs | Fixed offset from UTC, in seconds (east positive) | −43200 to +50400 | −18000 (UTC−5) |
| daysMask | Which weekdays the window opens on (bit 0 = Monday … bit 6 = Sunday) | 1–127, at least one day | 31 (Mon–Fri) |
| windowStartMin / windowEndMin | The daily window, in minutes after local midnight; the window is [start, end) | start < end ≤ 1440 | 540 / 1020 (09:00–17:00) |
| scope | 0 — every transfer is judged; 1 — only venue (trade) transfers are judged | 0 or 1 | 0 (all transfers) |
Enforcement. The engine reads the chain's Clock at every transfer, converts to local time with the fixed offset, and checks the day bit and the minute window — no state, no extra accounts, nothing to crank. A window cannot cross midnight in a single entry, and the launcher accepts one rule-12 entry per token, so one token gets one window per day. Config writes reject a zero mask, an out-of-range offset, and an inverted or over-long window. With scope 1, wallet-to-wallet sends move at any hour and only trades keep hours.
Example: The shipped defaults are the reference fixture — Mon–Fri, 09:00–17:00 at UTC−5. A trade at 16:59 on a Wednesday passes; the same trade at 17:00 is vetoed with OutsideTradingHours (error 28), as is any trade on Saturday. In November the window effectively runs on EST; in July, on the same config, it sits an hour off New York daylight time unless the config is re-issued at EDT.
Use it when… the token is meant to behave like a listed security — a work-hours asset, a market-hours experiment, or a token whose community lives in one timezone.
Verification status: Trial-proven; no mainnet launch carries it yet. The engine's v4 trial suite (73/73) runs the reference fixture under a controlled clock — inside/outside the window, day-mask edges, and the write-time rejections — and the worked spec example above is that fixture. The web composer exposes full controls for this rule — UTC offset, scope, window start and end, and the weekday mask — and the same fields can be set directly in the launch spec JSON.
Tokens unlock on a schedule instead of all at once. Each holder's position has an anchor — the balance-weighted average time they received it — and only an unlocked fraction of the position may leave the wallet. Spend past the unlocked fraction and the transfer is vetoed; the tokens themselves never move, nothing is custodied, and "released" simply means the veto lifts. Two legs can drive the schedule, and they compose as AND: a per-holder hold period counted from each position's anchor, and/or one global release date before which nothing unlocks for anyone.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| mode | cliff — nothing unlocks until the hold completes, then everything; linear — the unlocked fraction grows in proportion to elapsed time | cliff or linear | cliff |
| holdSecs | Per-holder hold period, counted from the position's anchor | Any duration; 0 turns this leg off | — (at least one leg required) |
| releaseTs | Global release time (unix timestamp): before it, the unlocked fraction is 0 for everyone | Any timestamp; 0 turns this leg off | — (at least one leg required) |
Enforcement. The gate sits on the sender, on every path — sells and wallet-to-wallet sends alike are judged against the sender's unlocked fraction. It passes when the post-transfer balance would stay at or above the locked share of the pre-transfer balance, and vetoes with VestingLocked (error 29) when it wouldn't. Receiving is bookkeeping, not a gate: every receive blends the position's anchor forward, balance-weighted, and a fresh position anchors at its first receive. A sender with no holder record at all fails closed with HolderMissing — every receive creates the record, so a missing one predates tracking; the remedy is a holder init plus a receive, never a silent pass. True self-transfers and pool-internal moves are ignored. A vesting clock with neither leg set is rejected at config write and at spec time — it would never unlock.
Example: Linear mode, holdSecs 7200 (two hours). You receive 1,000 tokens; one hour later half your position is unlocked. Sending 600 is vetoed — it would leave 400, below the 500 still locked. Sending 500 passes exactly. In cliff mode with the same hold, sending anything at one hour is vetoed, and everything unlocks at the two-hour mark.
Use it when… allocations should season before they can move — team and early-buyer vesting enforced by the token itself, with no escrow contract holding anyone's keys.
Verification status: Trial-proven; no mainnet launch carries it yet. The engine's v4 trial suite (73/73) pins both boundaries: linear at exactly 50% (send 501 vetoed, 500 passes), cliff at the second (3599 s vetoed, 3600 s passes), the global-release leg, and legacy holder records growing into the anchor field correctly.
Not launchable today. Read this first: no token can be launched with this rule through the standard launcher, and none ever has been. Decay Tax works by modulating a mint's Token-2022 Transfer Fee extension rate — and DBC creates every launch mint with a fixed extension set (metadata pointer, transfer hook, token metadata) that never includes the Transfer Fee extension. The launcher rejects a rule-14 spec at validation time, before anything is planned or signed, and the on-chain backstop fails closed too. What exists and is proven is the schedule program itself; the missing piece is a direct fee-extension mint path, which is not built yet. Everything below describes the mechanism as implemented, for the day that path exists.
The idea: a transfer tax that melts. The mint-wide fee rate starts high and decays linearly to a floor over a set period — early trading is expensive, patient trading is cheap, and the rate only ever moves down. The honest constraint shapes the design: a Token-2022 transfer-fee rate is mint-wide, one rate for everyone at a moment in time, so the decay is a schedule on the token's age — per-holder decay is not expressible in this mechanism at all.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| startBps | The transfer-fee rate at schedule start | 1–10000 bps | 500 (5%) |
| floorBps | The rate the decay lands on and never goes below | 0 to startBps | 100 (1%) |
| decaySecs | Time from schedule start to floor, linearly | Any positive duration | 2592000 (30 days) |
Enforcement. Not by the hook — the engine's Execute is a no-op for rule 14. The FeeSchedule program (66HUbm4tgcCsRkDL655UUrmm1aEVGugJzcYNm6NDFkFL) holds the mint's transfer-fee authority through a program PDA, and a permissionless crank instruction recomputes the target rate purely from the stored schedule and the chain clock — start minus (start − floor) × elapsed/decay, floor math — refuses anything outside [floor, start], and never raises the rate; when the computed rate isn't below the last scheduled one, it does nothing. Two pieces of fine print from Token-2022 itself: a newly set rate takes effect roughly two epochs after it is scheduled, and the extension's maximum-fee cap is read from the mint and passed through verbatim — this program never changes it. Initializing a schedule snapshots the parameters out of the token's engine config and fails closed with NoFeeConfig (error 3) on any mint without a Transfer Fee extension — the exact wall every DBC mint hits.
Example: The defaults, on a hypothetical fee-extension mint: 5% on day one, decaying linearly to 1% at day 30, and 1% forever after — a crank call on day 15 schedules roughly 3%.
Use it when… you can't, yet. When the direct fee-extension mint path lands, this is the launch-tax pattern: punish the first hours of sniping with a fee that melts to a fair standing rate.
Verification status: The FeeSchedule program is live on mainnet and its trial suite passes 52/52 (init snapshot, decay math, never-rises, epoch behavior), and the fail-closed wall is verified: an InitSchedule against a real DBC-shaped mint was exercised in live simulation on 2026-10-20 and fails with NoFeeConfig, as designed. The launcher's spec-time rejection is in the shipped code. No token carries rule 14, and none can until the mint path is built.
The token keeps a throne. A per-token record names the largest holder, and — when a tithe is configured — that share of every fee settlement is paid to whoever sits on it at settlement time. The crown is never assigned and never bought directly: hold more than the current king, observed on-chain, and the next transfer that touches your balance seats you. Lose the lead and the stream goes with it.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| titheBps | Share of each Distributor settlement paid to the current king; 0 = tracking only, no payment | 0–10000 bps | 0 (tracking only) |
Enforcement. Two halves, neither of which ever vetoes a transfer. The tracking half runs inside the hook on every transfer: a record (created lazily, funded from the token's rent vault) is refreshed whenever the reigning king is a party to a transfer — its stored balance follows the king's own post-transfer balance, up or down — and any non-exempt party whose post-transfer balance beats the record is crowned on the spot. Exempt accounts (pool and fee vaults) can never be king, and pool-internal moves don't touch the record. The payment half runs at settlement: the Distributor's DistributeWithSplits reads titheBps live from the config and pays that share of the net fold to the king the record names — last of the three split legs, after crown and seat. If nobody has been crowned yet, or the recipient doesn't check out, the leg skips and the share folds into the holder index. The stated limit is structural: a per-transfer hook can only observe balances when an account transacts, so the record is the largest holder as observed on-chain — a streaming maximum, not a global scan.
Composition. The settlement carves share one pot: at config write the engine rejects any stack whose Crown crownBps + Tithe Seat titheBps + King titheBps sum to more than 10000 bps. With titheBps 0 the rule is pure telemetry and composes with anything.
Example: At titheBps 200, a settlement folding 1 SOL pays 0.02 SOL to the current king. A challenger who accumulates a larger position takes the throne on the transfer that crosses the king's balance — and takes the 2% from the next settlement on.
Use it when… you want a standing prize for the biggest believer — a leaderboard with a revenue stream attached, where the top position is always contestable by simply holding more.
Verification status: Trial-proven; no mainnet receipt yet. The engine's v4 trial suite (73/73) covers lazy record creation, crowning, refresh-down when the king sells, and re-crowning; the Distributor's split trials (42/42) pay the king leg and skip it cleanly before any king exists. No mainnet token carries rule 15 yet.
The token's own trading fees buy the token and burn it. A crank watches the fees accruing to the token's fee claimer; once the claimable SOL crosses a threshold you set, it claims the fees, keeps a small caller cut for whoever runs it, market-buys the token on its own curve with the rest, and burns everything it bought. Supply falls by exactly the bought amount. It is the deflationary flywheel as a rule instead of a promise: no treasury decision, no discretionary buyback announcements — a threshold and a crank.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| thresholdSol (or thresholdLamports) | Claimable curve fees, in SOL, that must accrue before a buyback fires | Any positive amount | 1 SOL |
| callerCutBps | Share of the claimed fees the crank caller keeps for running the buyback | 0–1000 bps (max 10%) | 100 (1%) |
Enforcement. Nothing happens at transfer time — the engine's Execute is a no-op for this rule, and no transfer is ever judged by it. The work is crank-side, and it is deliberately paranoid: before signing anything, the crank re-validates that rule 16 is enabled with sane parameters and that the token's price feed is fresh — a stale feed aborts the pass with zero transactions signed. Only then: claim the curve fees, check the threshold, take the caller cut off the claimed amount (floor math), buy through the hook-aware swap on the token's own curve, and burn from the crank's own account — burning your own tokens needs no mint authority, and it is the only supply-reducing move; sending to an incinerator address would strand the supply and is never used as a fallback. One operational fact decides whether a rule-16 token actually gets its buybacks: only the token's fee claimer of record can sign the fee claim, so a token is crank-operated in practice only when it was launched with its fee claimer set to the crank wallet. The platform's live crank service runs the buyback pass on its rounds — and today it has nothing to act on, because no launched token carries rule 16.
Composition — stated plainly. Rule 16 and holder-fee routing draw on the same accrued SOL (the claimer's curve fees), and older skill and composer copy described them as mutually exclusive. They are not: no engine- or launcher-level check rejects the combination — a spec carrying both launches today, and the two are separate paths over that one balance (holder fees are claimed at the fee claimer, converted, and settled to holders through the Distributor; the buyback crank claims at the fee claimer and spends what it claimed on the buy-and-burn). Which path claims a given accrual is an operational choice, so design the stack knowing both may draw on it.
Example (the proving trial): claimable fees 2.5 SOL against a 1 SOL threshold at the default 100 bps cut: the caller kept exactly 0.025 SOL, 2.475 SOL bought the token through the hook, every bought token was burned, and total supply fell by exactly the bought amount. A second pass with nothing new accrued did nothing, to the lamport.
Use it when… the token's story is fee-funded deflation — trading activity itself retires supply, mechanically, at a threshold anyone can verify and a crank anyone designated can run.
Verification status: Trial-proven; no mainnet receipt. The buyback trial passes 45/45, twice, deterministically — real DBC binary, a Basis Latch token as the hardest case, the stale-feed abort signing nothing, supply deltas exact. Two substitutions are on the record: the scenario's accrued fees were injected at scale (the claim mechanism was separately probed for real, claiming 2,400,000 lamports of genuinely accrued fees), and the trial's rule-16 config entry was byte-patched in-SVM, with the engine write path proven separately (46/46). Post-graduation DAMM LP-fee claiming is unproven, and the standalone crank CLI ships local-only — the live path is the crank service's buyback pass.
Receiving this token requires more than a registration — it requires a registration attested through a named ecosystem's own flow: a Muse flow, a Fomo flow, a Claude or Grok flow. The Registry record carries an ecosystem tag, and the tag can only land when both the wallet and that ecosystem's designated attester sign — a wallet cannot tag itself, and nobody, the registry authority included, can tag a wallet without the wallet's own signature. What the tag proves is provenance: this wallet was created through that ecosystem's enrollment flow, with that ecosystem vouching for it. What it never proves is what operates the wallet day to day — the pages here claim the first thing, never the second. Put plainly: the ecosystem's skill is the key-cutting machine, its attester is the locksmith, and the Registry stamp is the lock.
| Parameter | Meaning | Valid range | Default |
|---|---|---|---|
| ecosystem | The ecosystem whose attested registration a receiver must hold: "muse" (1), "fomo" (2), "claude" (3), "grok" (4), or any id 1–16 (the named aliases "muse-only" etc. resolve to the same ids) | 1–16 | None — required, or an alias that names one |
Enforcement. Every receive is judged, venue trades and wallet-to-wallet sends alike, against the destination's synced Registry mirror — the same mirror rule 3 uses, carrying one extra byte for the ecosystem tag, both written together from the same Registry snapshot so they can never describe different records. Three outcomes: registered and attested for the required ecosystem passes; not registered at all vetoes with NotRegistered (error 1 — the remedy is the same as rule 3's: register, attest, sync); registered but attested for a different ecosystem — or for none — vetoes with WrongEcosystem (error 24). Exempt destinations skip the check, and a config naming ecosystem 0 or anything above 16 is rejected at config write. The mainnet state today, stated plainly: the Registry's ecosystem config exists and exactly one attester is configured — Muse, preset 1, set 2026-10-16. Presets 2–16 are unset, so no other ecosystem can attest a wallet yet; a gate naming one of them would pass nobody, which is why the launcher warns about exactly that at spec time.
Graduation. A hook rule like the others: it retires with the hook under release graduation, and keeps judging every receive forever under never or house. Registrations and attestations themselves live in the Registry and are untouched by any token's graduation.
Example: A muse-gated token. A wallet that self-registered but never went through the Muse attestation flow is vetoed with WrongEcosystem; a wallet with no registration at all is vetoed with NotRegistered; a wallet whose registration carries the Muse tag receives normally.
Use it when… a token belongs to one agent ecosystem's members — minted for the wallets that ecosystem actually onboarded, not for anyone who can sign a transaction.
Verification status: Trial-proven, with its mainnet substrate live; not yet carried by a launch token. The ecosystem integration suite passes 28/28 (attested registration, tag writes under dual signature, both veto errors) inside the engine battery, and the Muse attester is configured in the mainnet Registry. No token has launched with rule 17 yet, so there is no mainnet token receipt.
Compatibility on this page is not a matter of taste: it is whatever two validation layers accept, and this section is derived from those layers — never inferred from the panels above. The first layer is the launcher's spec validation (validateSpec in launch.mjs), which runs before anything is planned or signed. The second is the engine's config-write validation (parse_config_payload in the engine), which runs on-chain when a token's config is written. A combination neither layer rejects is allowed — full stop. Rules are otherwise independent: they evaluate in stack order on every transfer, and the first veto ends it.
| Constraint | What the code does |
|---|---|
| At most 8 rules per token | The launcher throws on a ninth rule; the engine's MAX_RULES is 8 and its config write enforces the same cap. |
| Each rule at most once | The launcher rejects a duplicate rule id in the stack. The engine itself would store two entries with the same id — its own Trading Hours comment even imagines stacking two rule-12 entries for a split day — but through this launcher a rule appears once, so a token gets exactly one Trading Hours window per day. |
| Known, implemented rules only | Both layers reject an unknown rule id, and an id the engine build cannot enforce — a config may never claim a rule its Execute would skip. |
| Rule 14 (Decay Tax) in any stack | Rejected by the launcher at spec time, unconditionally: DBC mints cannot carry the Transfer Fee extension the rule schedules. Rule 14 therefore pairs with nothing through the standard launcher — it is structurally N/A, not merely untested. See its panel. |
| Combination | Verdict | Why |
|---|---|---|
| Rule 2 (Escrow Split) without rule 1, or without graduation house | Required together | The launcher throws if either is missing: escrow resolution reads the price feed and the seller's basis that only rule 1 maintains, and the split itself lives in the house venue's swap — a curve token has no venue to split in. The engine independently refuses a rule-2 config that carries no house commitment block. |
| Rules 5 + 6 + 15 with crownBps + titheBps + titheBps over 10000 bps in total | Forbidden | The three settlement carves share one pot. The engine rejects the config write when the sum exceeds 10000 bps, and the Distributor re-checks the same sum at settlement time and hard-errors (SplitBpsTooLarge) before anything moves. |
| Rule 4 (App-Gated) naming an app that is not in the config's venue allowlist | Required | Caller validation runs before any rule is consulted: a trade whose executing program is not allowlisted as a venue is rejected outright, so an unregistered app never gets a trade for rule 4 to judge. The launcher writes the DBC program as the venue — list it as an app if plain curve trades should pass the gate. |
| Combination | The missing condition | What happens meanwhile |
|---|---|---|
| Rules 5, 6 or 15 on a token launched without holder fees | A Distributor — created at launch only when holder fees are on (feeDestination "holders") | The configs write and read fine, but there are no settlements, so the carves never pay. The rules are settlement-side by design; with no settlement stream they do nothing. |
| Rule 5 (Crown) before the token's Crown Init | The one-time Crown Init that creates the token's crown record | The crown leg skips every settlement (it fails open) and its share folds into the holder index instead. |
| Rule 6 (Tithe Seat) with no valid seat position | A seat account holding exactly 1 of the seatMint, checking out at settlement time | The seat leg skips and its share folds into the holder index. |
| Rule 15 (King) tithe before any king exists | A crowned king — a transfer that seats one | The king leg skips and folds to the index. The tracking half runs from the first transfer regardless; at titheBps 0 the rule is tracking-only by design. |
| Rule 17 (Ecosystem Gate) naming an ecosystem with no configured attester — presets 2–16 today | That ecosystem's attester configured in the Registry, and its enrollment flow running | The gate enforces and passes nobody: no wallet can hold the required attestation yet. The launcher warns about exactly this at spec time. |
Older composer and skill copy described Buyback & Burn and holder-fee routing as mutually exclusive. That wording was never backed by a check: not in the launcher's spec validation, not in its fee resolution, not in the engine's config write — all three were searched for this section, and no rejection exists in any of them. The copy now says what the code does. A spec carrying rule 16 with holder fees on launches today, and the two mechanisms are separate paths over the same accrued fees: holder fees are claimed at the fee claimer, converted, and settled to holders through the Distributor, while the buyback crank claims at the fee claimer and spends what it claimed on the buy-and-burn. Both draw on the same accrued balance, so which path claims a given accrual is an operational choice — plan for it when you design a stack, because the code leaves it to you.
Where the liquidity comes from. Bonding-curve liquidity comes from the curve's virtual reserves — nobody deposits LP up front. Buys pay SOL in and mint tokens out along the curve; sells reverse that, so SOL accumulates in the pool as the token sells.
Graduation. When the curve raises the migration threshold in the spec (AGTR: 42 SOL), the token graduates: a real DAMM v2 pool is created and the transfer hook is revoked in the completing swap — rules end, trading continues free.
Graduation is a launch-time choice. The spec field graduation picks the token's future at launch. Release (the default) is the behavior above: migrate at the threshold, hook revoked, rules retire, trade anywhere. Never sets the migration threshold to the maximum the venue accepts — 18,446,744,073,709,551,615 lamports (u64 max, ≈18.45 billion SOL — more than exists) — so the curve never completes: the token lives on its curve with the rules enforced forever, the 20% migration share stays locked in the pool, and only hook-aware doors can ever trade it. A third option, house, graduates the token onto our own venue (the HouseSwap program) with the rules intact: the hook is not revoked, the engine keeps judging every transfer, Escrow Split keeps settling on house trades, and the curve remains open as a legacy door. House graduation is live — HPROOF activated it on mainnet on 2026-10-20 (receipts on its preflight report).
Who gets the trading fee — the creator fee. The curve charges a trading fee on each trade. Its rate is set in the launch spec (feeBps, default 100 bps = 1%, allowed 25–9900 bps — the venue program's own bounds), and it accrues to the DBC config's fee_claimer, which for a launch is the deployer's wallet. The transfer hook never touches the fee — hooks can only veto; this is venue-fee direction set at launch. The deployer collects it with one command (node hook.mjs claim-fees), straight from Meteora — no APIs, no platform cut.
Holder fees change the destination, not the fee. With holder fees ON, that claimer stream is instead routed to holders: the claimer runs that same one command — it claims, converts the fees into the token, deposits them into the token's Distributor vault, and cranks the fold — and anyone else can crank further deposits into the pro-rata index (the crank caller keeps callerCutBps, default 100 bps of the fold).
What launching costs. Deployer cost recap: ≈0.065–0.075 SOL of launch state per launch (AGTR measured 0.0704 all-in) plus an optional seed/first buy of the deployer's choosing; program deploys were a one-time platform cost, not per-launch. Standing duty near graduation: keep ≈1–2 SOL available for migration flash rent.
Every launch is tagged. A launch's creation transactions (config + pool) each carry one extra instruction: an SPL Memo with the fixed text hook-launcher:v1, signed read-only by a dedicated tag key — the platform launch signer (95uGAjvVB3xLkqdGZoq2CncLunqcUPe8NxhetRVkiVgF). The memo changes nothing in the transaction — the extra signature is a label, so terminals and routers can spot Hook Launcher launches at a glance, and scanning that one address's signatures enumerates every launch. The key is fundless and powerless by design (in the browser composer it is embedded in the bundle; the worst case is a spoofed label, never funds). Treat the tag as a hint, not proof: the real attestation is on-chain — the token's engine config and hook meta list.
A launch can bundle its first buy. The optional spec field devBuySol (up to 10 SOL) makes the launcher buy that much of its own token inside the launch run — after registering/syncing itself when a gate rule requires it, and after cranking the price feed when Basis Latch is on. The honest bound: the buy is its own transaction, submitted immediately after activation — the first swap after activation, but not atomic with it, because a swap can only be built once the token's on-chain hook meta list exists. A third party landing in an earlier slot could theoretically precede it. With devBuySol unset, nothing changes: no buy, same plan, same transactions as always.
Nothing here was trusted on argument alone. Before mainnet — and for every rule added since — the engine, its settlement programs, and its venue integration ran in simulation: LiteSVM trial suites throughout, with the venue suites running against the real Meteora DBC binaries:
| Trial | Result | What it covered |
|---|---|---|
| Engine suite | 64/64 assertions | The rule engine itself: every live rule, config writes, vetoes. |
| DBC integration | 40/40 | The engine running inside swaps on the real Meteora DBC program binaries. |
| Latch-on-curve | 55/55 | Basis Latch end-to-end on a real curve: basis, veto, dip, latch, free exit. |
| Graduation | 46/46 | The launcher's graduation suite: curve completion, hook revocation, DAMM v2 migration. (The original standalone graduation proof passed 22/22.) |
| Engine v4 trial | 73/73 | The v4 rules end-to-end in the engine — App-Gated, Allow/Blocklist, The Grudge, Trading Hours, Vesting Clock, King tracking: vetoes, boundaries, and write-time rejections. |
| Settlement config validation | 46/46 | Engine trial-phase-b: config writes for the settlement rules (5, 6, 14, 15, 16), the cross-rule split-sum rejection, and the Execute no-op arms. |
| Distributor split trials | 42/42 | Settlement split payouts — the crown, seat, and king legs — including the skip-and-fold behavior when a leg's record is absent or wrong. |
| Crown trial | 66/66 | The Crown seat program: init, the challenge game, finalize, and the slash math — every lamport exact. |
| FeeSchedule trial | 52/52 | Decay Tax's schedule progression on fee-extension mints — LiteSVM only; no mainnet mint can carry the extension yet (see rule 14's panel). |
| Buyback trial | 45/45 | The rule-16 crank library: its preconditions (including the stale-feed abort that signs nothing) and the claim → buy → burn flow. |
| Ecosystem-gate integration | 28/28 | Attested registration, dual-signature tag writes, and both rule-17 veto errors. |
| HouseSwap trial | 87/87 | The house venue's swaps and both Escrow Split resolution branches — the dip refund and the above-entry forfeit. |
| Launcher house trial | 37/37 | House launch account lists and client builders, including the cases the HPROOF mainnet defects added. |
Then the AGTR mainnet proofs, run live on the genesis token: the launcher wallet registered, synced, and bought 0.05 SOL → 3,758,140.828991 AGTR landed — exactly the amount the pre-launch trials predicted. A fresh unregistered wallet's identical buy was vetoed with NotRegistered and received 0. The full record is public: agentonly.fun/hooks/agtr-record.json. The proving method — and everything else building this taught us — is written up in What we learned building Solana hooks.
Engine v3 is the live engine (upgraded in place on 2026-10-16; upgrade tx 3wt6DhFi…). One change, three consequences:
Account-keyed holder records. In v2, a Holder PDA's address was derived from the contents of the holder's token account (an AccountData seed over the account's owner field). The standard resolver every router uses — spl-token's addExtraAccountMetasForExecute, which the Meteora DBC SDK calls internally — must read that account to build the address, so for a first-time buyer, whose associated token account doesn't exist yet, resolution threw TokenTransferHookAccountDataNotFound and generic first buys failed. In v3 the seed is the token account's address (AccountKey): for an associated token account that address is a pure function of owner + token program + mint, computable before the account exists. Verified live: before the flip the resolver threw for a fresh wallet on both AGTR and Latch; after it, the resolver resolves for a fresh wallet on both, and each token's meta list publishes only the extras its own rule stack needs (AGTR's list is now 191 bytes, 5 extras).
What holders of v2-era tokens do. Two instructions carry existing state across. MigrateHolder (permissionless — anyone can crank it) copies a legacy owner-keyed record verbatim to the account-keyed address, funded by the token's rent vault, and closes the legacy account back into the vault; the retrofit crank for AGTR + Latch migrated all 7 records this way, each byte-equal, none stranded. SyncHolder (owner-signed; CLI: node hook.mjs merge <token account>) merges one of your token accounts' records into another's: registration and ecosystem mirrors OR together, the latch ORs, basis blends balance-weighted against live balances, peak takes the max, the earned cap takes the min of the summed caps and the merged peak, and the source record closes to the vault. The CLI's node hook.mjs migrate runs the first; merge runs the second.
The disclosed trade. Holder identity is now the token account, not the owner. For the canonical associated token account — the account wallets and routers actually use — the two are exactly equivalent. State held across one owner's extra token accounts fragments per account until merged: basis carries correctly per account, an earned graduated cap is per-account until merged, and receives into a non-ATA account start unregistered and fail closed. Fragments can only ever be more locked, never less. This is the same multiplication that always existed via fresh wallets; the merge instruction is the repair.
The deploy, honestly. The first v3 window failed: the meta-list refresh shrank the launch-era 261-byte lists before updating them, leaving a stale TLV length, and the flip panicked in simulation (never sent). The window rolled back to the exact v2 binary and verified byte-identical state. The fix — update first, then resize, rent settled neutrally to exact exemption — was rehearsed against the preserved real list bytes (83/83, including the shrink case with the rent refund exact to the lamport) before the second window landed end to end. The full record is the deploy record in the source tree.
What the engine is. Six Solana programs. The Engine (EPdYVfsX7Lk9gtLp8CVouiFrNwtxP5g11NR6DDgs6akT) is the transfer-hook rule engine itself. Its companions: the Registry (self-signed wallet registration, with optional ecosystem attestation), the Distributor (per-token fee vault + cumulative index, permissionless crank), the Crown (the contestable beneficiary seat the settlement splits read), the FeeSchedule (the Decay Tax rate schedule on fee-extension mints), and HouseSwap (the house venue whose swaps keep enforcing the rules after house graduation). A token's behavior is a per-mint Config PDA: an ordered stack of up to eight rules, each a rule id + a 64-byte parameter block, plus an authority mode (Locked / Creator / Agent / HolderVote), a venue allowlist, and exemptions. Per-holder state lives in Holder PDAs; the Basis Latch reads a cranked PriceFeed PDA. Rules are data — a new ruled token needs a launch, not a deployment.
Where the code lives. The full source tree is public as one repository: github.com/anondevv69/hook-launcher — the six program sources under programs/ (engine, registry, distributor, crown, feeschedule, houseswap; each a single-crate Rust program), the launcher under launcher/ (launch.mjs, hook.mjs, the browser composer sources), the design specs (the engine-v3 study, the graduated-latch and ecosystem-gate specs, the graduation and House specs), and the deploy records. Its VERIFY.md walks the hash check that proves the deployed programs match that source — the same check the next paragraph describes. The launcher CLIs and the agent skill are also public on this site.
Verify the deployed program against the source. The live engine binary is 318,144 bytes, sha256 87d31f834d31026f4492dd718f4f07d69897a8b2dd8b1257dc5c188cecc398cb. The build is byte-reproducible: build the engine crate with the Solana toolchain and compare the hash to the bytes in the program's programdata account (offset 45 onward) — the deploy record documents the same check passing at upgrade time. If your build's hash differs, you're not looking at the program these tokens run.
How a new rule gets added — the real path. There is no plugin API: a new rule is an engine change, and every live rule took the same four steps. (1) A written spec — parameters inside the 64-byte block, semantics stated exactly, and hook-pure: enforceable by the transfer hook alone (read/write its own state, veto). If the hook can't enforce it alone, it doesn't ship. (2) An implementation in the engine's rule dispatch — evaluation in stack order inside Execute, and config-write validation that knows the id (unknown and unimplemented ids are rejected at config write, by name). (3) Proof — LiteSVM trial suites against the real Meteora binaries, with the existing battery staying green; rule semantics are post-transfer, because Token-2022 applies the transfer before the hook runs. (4) Ship — an engine upgrade by the upgrade authority, a catalog entry here with its status set honestly (below), and the composer/skill surfaces updated in the same window. To propose a rule, bring the spec and the implementation to that bar; that's the whole process, and it's the same one we'd hold our own rules to.
Claims on these pages follow one discipline, so you can price them:
| Label | Meaning |
|---|---|
| Live | Running on Solana mainnet today, in the form described. All 17 catalog rules are live in the engine, and the settlement programs are deployed alongside it — the Distributor with the first launches, and Crown, FeeSchedule, and HouseSwap on 2026-10-20. The release and never graduation options, and house graduation (live since the HPROOF mainnet proof, 2026-10-20). Live in the engine is not the same as mainnet-proven per rule: thirteen of the seventeen are so far proven in trials only — Basis Latch (1), Escrow Split (2), Agent-Only (3) and Max Wallet (9) are the four a live token has exercised — and each rule's panel above states its own status — believe the panel, not this row. |
| Built | Implemented and suite-proven, but not yet carried by a live token or not yet selectable in the composer — labeled where it appears. |
| Design-stage | A written spec only; no code claims. The direct fee-extension mint path — the unblock that would make Decay Tax (14) launchable — is here: specced, not built. |
| Specced | Catalog entries with a design and a rule id, not yet implemented. The launcher rejects them by name; nothing on these pages presents them as available. |
The story of the engine, the failed window included, is told in full in Everything here is a hook.
Launches feed: GET https://agentonly.fun/api/launches — keyless JSON listing every AgentOnly launch (name, symbol, mint, pool, configs, rules, graduation mode, metadata URI, page, pool creation time, status), generated from the launch records reconciled against chain state and republished at the end of every launch. Statuses tell the truth per token — a paused or incomplete launch is labeled as one, never as trading. The same document carries the partner identity block: name AgentOnly, website agentonly.fun/hooks/, partner-metadata account 6udQdVvbGyGk5BcdEjZoAbqvLWmQsf7F1d1zjDu8ZGmU (DBC partner metadata, fee claimer FMYVMuJgoM9J41PaXBmJe6ijSHUtSr2VPRbAJvH4MhCP), and the launch signer 95uGAjvVB3xLkqdGZoq2CncLunqcUPe8NxhetRVkiVgF — every launch's creation transactions carry that key as a read-only signer, so one signature scan enumerates the whole catalog.