Safety

What is not built yet

The program is live on mainnet, which makes this page more important rather than less. Everything below is specified, or partly specified, and does not work today. This page exists so nobody has to discover any of it the hard way, and it is the page to read before treating anything else on this site as a promise.

It is deployed, and nothing has launched on it#

Live on mainnet since 2026-09-23

Program 4fhFQ8hgbswQq7PNsrwCcxkpE1oae6fsFcLvAjWEnPhD, Config initialised, 6 origins and 21 models written, launch readiness 12 of 12. This page used to open by saying none of that was true.

Coins have launched, and fees have routed through them

Two policies are live on mainnet, one Passive and one Agent, both quoted in GOOGLX. The whole fee path has run end to end: a launch, fees arriving in quote_escrow, route splitting them, a venue account registered, and agent_fund_venue moving the bankroll share out. Every split measured exact, with nothing lost to rounding.

Some API examples on this site are still captured against a local validator with fixture mints, and a counter shown in one of those is a fixture counter. Where a figure is from mainnet the page says so.

The admin key is permanent, and so is the risk floor

Config.pending_admin exists in the struct and nothing reads it. There is no accept_admin instruction, so there is no admin handover path at all: whoever holds the key that ran initialize is permanently the only key that can register an origin or a model, change any protocol parameter, or pause the protocol. There is no recovery if it is lost and no rotation if it is exposed.

min_risk_for_class is the other set-once field, currently [0, 0, 0, 10, 80, 80, 0, 0], so the risk 80 floor for perps and options is permanent too. Everything else, including protocol_fee_dest and the reporter, is changeable by the admin. An earlier reading of this had the fee destination in the permanent column; it is not.

Fees arrive, and the headline counter reads zero anyway#

The revenue path is real, and it was watched rather than read about

A Stags launch is StonkFun's standard mode on LaunchLab, which has no creator position to claim from. StonkFun collects the pool's 1% fee and forwards the creator's share itself, and the policy PDA is the pool's creator.

The forwarder is 5CEbueQnq1Ym2uSSx2xXds3jQAqT1BDnkA59RZobSPAG, which is not an inference: it is the platform_fee_wallet field of StonkFun's live platform config, decoded on chain, and it is the fee payer and token authority on every credit observed. A forwarding transaction is two instructions, a createIdempotent for the creator's quote associated token account which StonkFun pays for, then a transferChecked into it. No CPI and no LaunchLab involvement.

The destination is ATA(creator, quote_mint, token_program), which is exactly this program's quote_escrow. Forwarded fees land in the account route already reads, so the "sweep" this page used to call an unwritten blocker turned out not to be needed at all.

LaunchQuoteStatusWhat was observed
STONK10wSOLmigrated35 of 35 credits from the fee wallet over 3h19m, 13.62 SOL, median gap 299s
POKEMONCARDSmigrated25 of 25, every 15 to 50 minutes
DATANAan xStock, Token-2022migrated10 of 11 signatures are credits, every 5 to 40 minutes
SCATSPYX, Token-2022still bonding8 of 8 from the fee wallet, median gap 1035s
TKCDJT, an xStockstill bondingcredited from the fee wallet

Five real launches, read on chain on 2026-09-23. Forwarding is observable in the pool's quote token only, both before and after graduation, and on Token-2022 xStock quotes, which is exactly the case this product ships. On every one of them LaunchLab's own creator_fee_vault reads 0, which is the negative control: the vault is genuinely not the mechanism.

Nothing on chain commits StonkFun to any of this

A cadence is an observation of the recent past, not a guarantee. Nothing commits StonkFun to forwarding at all, to any particular share of the 1%, or to any interval, and a launch StonkFun does not adopt gets no forwarding. Adoption is a live dependency of this product's revenue, and it is the single largest thing on this page.

Policy.fees_claimed reads zero forever on this launch type

fees_claimed and the FeesClaimed event are incremented only by claim_fees. route increments protocol_fees and routed_to_bankroll and emits Routed, but never touches fees_claimed. On a forwarded launch nothing is ever claimed, so the headline revenue counter stays at zero while real fees flow, and no FeesClaimed event is ever emitted.

The indexer and the front end under-report this launch type as a result. The front end explains the counter rather than hiding it, which is honest, and the fix belongs in the program: either route credits what it routes, or a FeesSwept event is added. Neither is written.

A taxonomy correction this site used to repeat

"LaunchLab" is not a third launch type beside standard and reward. The two fields are separate: launchpad is launchlab, or raydium for the older locked-position and Fee Key NFT type, and mode is standard or reward. Forwarding is the standard mode's mechanism. Reward mode has no creator fee at all, its transfer tax going to holders instead.

The on-chain measurement, which stands and does not contradict this#

Both live StonkFun platform configs, decoded from mainnet on 2026-09-22, are byte-identical on the fee fields. Re-verified on 2026-09-23 against a brand new, still-bonding mode: standard launch, GCAT, pool 2xiq18PpZZuFopgoCvzNqCtRAjcsreDPWYV3rv5SPgVd, pointing at standard platform config 4E876qZTE9FJMrBzgVtBrSrzz2TLivB5Y5QXPjB4gZL7.

FieldStandard configReward config
creator_fee_rate00
fee_rate10000 (1%, collected by StonkFun)10000
creator_scale00
platform_scale1000000 (100% at the protocol level)1000000
burn_scale00

Corroborated three independent ways:

  1. Every creator fee vault behind all 25 live launches reads exactly zero, including pools with 476k and 1.4M quote units of real quote traded through them.
  2. A mainnet simulation of the claim reaches LaunchLab's own handler and fails with RequireGtViolated, Left: 0. Every account was accepted and control reached the handler; there was simply nothing to transfer.
  3. The post-graduation path is the same: creator_scale = 0 means no locked LP position is handed to the creator at migration, and amm_creator_fee_on = QuoteToken only selects which token such a fee would be denominated in.

Why that is consistent rather than contradictory

creator_fee_rate = 0 with platform_scale = 1000000 is exactly what you would expect when the platform takes the whole 1% at the protocol level and then forwards the creator's share itself. The creator fee vaults are empty because that path is not the one in use, not because nobody is paid. Both facts are true at once, and an earlier version of this page drew the wrong inference from the right measurement.

One open product question falls out of this. The older Raydium launchpad type pays through a locked position and a Fee Key NFT, in a documented share that arrives in both tokens of the pair, and it is a different type from the one this launch flow builds. Whether this product should target it instead is open rather than settled.

There is no LP position to compound into#

compound_lp has nothing to compound into, and a keeper cannot create one

The compounded liquidity is a Meteora DAMM v2 position the policy owns. No such position exists, and a permissionless keeper cannot make one: create_position needs a signing NFT mint keypair and a rent payer, neither of which a keeper has. Creating it belongs to the launch flow or to a one-off operator bootstrap, and it is not written.

And a quote-only inflow does not compound into a two-sided pool

Meteora pulls both tokens in the pool's ratio. Both LaunchLab's creator fees and StonkFun's forwarding are quote only, and the only base the program holds is the pending burn, which is spoken for. So even with a position, a quote-only balance cannot be added as-is. The ways out are all product decisions and none of them is taken.

Derive cannot be provisioned, so options do not exist#

Two Derive write endpoints are failing, and they are the two that matter

Provisioning a per-token options vault needs a subaccount and a scoped session key. Measured on 2026-09-23, from the same machine and in the same minutes that Derive's read endpoints answered 200:

  • private/set_session_key, which mints a scoped key, returns [-32603] Internal error (null) for every valid payload. A malformed one correctly returns -32602, so the server parses the body and then throws.
  • public/register_deposit_address, which is the only thing that creates a subaccount, returns HTTP 503, five attempts in a row.

So a per-token options vault cannot be created, and how many subaccounts one wallet may hold could not even be measured. This is a venue limitation on write paths, stated without blaming anyone: Derive's design is the right one for this product, and two of its services are returning errors.

A claim this site made that was false, and why

This page said Derive v3 had zero mainnet option instruments, and concluded that options would have to ship on v2 with an unscoped key that can withdraw. Both halves were wrong and the error was ours. The probe called public/get_instruments, which is v2's endpoint name and returns 404 on v3, inside a try/catch that counted every failure as "this currency has no options". Run across 35 currencies that produced a confident zero, which was then written down as a measured finding.

Through the correct endpoint, public/get_all_instruments, v3 carries live option markets on ETH, BTC and SOL and scoped session keys, and the account this project funded lives on v3. There was never a trade-off between liquidity and a scoped key. The venue detail is on venues.

What that leaves: the options origin is registered on chain, the risk model has a page, and no options position has ever existed. Every rule on risk in options is a rule for a position that cannot yet be opened.

The bridge is operator-run, and that is the honest word for it#

Value has crossed, once, on mainnet

On 2026-09-23, 20 USDC moved from Arbitrum One into Hyperliquid's bridge and landed in the perp account, an agent key was approved on that account, and the agent key filled a real order. Until that day no value had ever reached a venue in this project, and this page said so.

Nothing about it is trustless, and nothing is expected to be

A Solana program cannot verify an OP Stack L2 or a separate L1. agent_fund_venue pays a Solana token account the authority registered, and from there an operator-run relayer swaps to USDC and pays out of a float it already holds on the EVM side. If it takes funds and does not deliver, remote_equity never rises, the gap against bridged_out is visible on chain, and the deviation rail pauses the policy at the next attestation. That is a bound on the damage, not a guarantee of delivery.

The relayer has carried value on the EVM side only. The Solana hop is proven separately, including that funding an unattested Remote venue correctly fails with StaleRemoteEquity. See remote equity and attestation.

Volume does not exist#

There is no trading volume anywhere in the indexer. Not per coin, not per quote, not protocol-wide, not in the database schema. The word does not appear in the indexer source at all.

Nothing in the API returns a zero for it either, which is the important part: an endpoint that had volume and could not compute it would say so. There is simply no field.

Why it is missing rather than wrong

The indexer is built from the bankroll program's own events plus direct account reads. Trading volume happens in the LaunchLab pool and later in the graduated pool, neither of which emits anything this program sees. Computing it would mean indexing Raydium, which this build does not do.

Market cap stops at graduation#

Market cap is computed from the Raydium LaunchLab pool account: the curve price multiplied by the pool's own supply field. That works while a launch is still on its bonding curve. Once it graduates onto a CPMM pool, the price has to be read from that pool instead, and this build does not do that read.

Pool statusMeaningMarket cap
0Fund, on the bonding curveLive
1MigrateNot read
2Trade, graduatedAbsent, with a reason
nullno pool account exists at allAbsent, with a reason

PoolStatus values are Raydium LaunchLab's own.

The USD figure is a separate link again, and can be missing on its own: it needs a price for the quote, which comes from StonkFun, and a quote StonkFun has never listed has no first-party price. A cap denominated in the quote asset that is true is reported in preference to a dollar cap that is guessed.

There is also no market-cap ranking. /rankings?by=marketCap returns available: false with a reason rather than an empty or sorted-by-something-else list.

GET /rankings?by=marketCap
{
  "by": "marketCap",
  "available": false,
  "reason": "live per-token market cap requires reading the launched token's LaunchLab/CPMM pool account directly on chain. The bankroll program's events and StonkFun's public API (opening/graduation market cap of the QUOTE, at launch time only) do not carry this. Not implemented by this indexer yet.",
  "rows": []
}

222 of 509 pairs cannot launch#

A single shared token_program forces Token-2022 on both legs

init_policy takes one token_program account and uses it for every token account it creates. The base mint is always created by LaunchLab's initialize_with_token2022, so that program must be Token-2022, and a quote mint owned by the classic SPL Token program therefore cannot be paired.

222 of the 509 launchable pairs in StonkFun's catalogue are classic SPL, re-derived on 2026-09-23 by reading every mint account from mainnet. They appear in the picker and fail at init_policy. All 24 tokenized stocks are unaffected.

This is a separate and still-live limitation, and it is narrower than it sounds. All 24 xstock pairs are Token-2022 at 8 decimals, so the tokenized stocks are untouched by it; the problem is concentrated in the custom category, where the catalogue is close to an even split. Full breakdown on quote assets and pairs.

Venue instruction builders are not written#

claim_fees, compound_lp and buyback_and_burn forward an opaque instruction supplied by the caller to a pinned program. The specification's plan is for the program to build those instructions itself, in src/venue/launchlab.rs and src/venue/meteora.rs, so callers stop constructing venue instructions by hand. Neither file exists.

The consequence is described precisely on the safety model: the measured-delta checks guarantee honest accounting, and they do not guarantee that the caller constructed a good trade. The program cannot check the price, the route or the destination of a swap whose layout it does not know.

Claims this site does not stand behind#

Either untested, or tested and found false. Each row says which.

ClaimStatusWhat would settle it
A Hyperliquid agent wallet cannot withdraw or transferUnverified. Supported by two statements in the official SDK, but the server-side authorization matrix is closed source and whether subAccountTransfer and vaultTransfer specifically are agent-blocked is stated nowhere. An approved agent key now exists and has traded, so the old excuse, an unfunded account, is gone. The probe still has not been run.Attempt usd_transfer, withdraw_from_bridge, sub_account_transfer and vault_transfer with the agent key, confirming each is rejected.
Derive v3 has no mainnet options bookFalse, and retracted. It was our own measurement bug: a v2 endpoint name called against v3 inside a catch that read every 404 as an absent market. v3 has live option markets and scoped session keys.Already settled, through public/get_all_instruments. The decision it was used to justify, shipping options on an unscoped v2 key, is withdrawn with it.
An options position stays inside the risk modelUntestable today. No Stags options vault exists and one cannot be provisioned, because two of Derive's write endpoints are failing.Derive's own service returning to health, then a provisioned subaccount and a scoped key per launched token.
Options positions stay defined-risk and within 5x deltaEnforced off chain only, by the agent runner. The program has no notion of delta.It cannot be enforced on chain. The honest statement is that this is a policy of the runner, not a property of the program.
The venue's own per-asset leverage is set to at most 5Off chain, and therefore trusted.Nothing on Solana can check it. Two of the three leverage checks are on chain; this is the third.

Smaller gaps, for completeness#

GapDetail
compound_lp emits no eventPer-call history for LP compounding does not exist. Policy.routed_to_lp, from the account snapshot, is the only authoritative cumulative figure.
The base fee leg has no on-chain counterPolicy.fees_claimed accumulates the quote leg only. Base-leg totals come from summing indexed FeesClaimed events, so they depend on the indexer rather than on the chain.
Config.pending_admin is never usedThe field exists on the account and is set to the default key at initialize. Nothing reads it and there is no accept_admin instruction, so there is no two-step admin handover.
tokens_burned cannot be split by sourceOne counter covers both the unconditional base fee leg and the profit-funded buyback. Separating them means reading events.
There is no set_guardianThe guardian key is whatever was passed at init_policy, for the life of the policy.
A PDA-owned Meteora position has never been observedIt is inferred from Meteora's own constraints (create_position takes owner as an unchecked account, not a signer) and from its CPI documentation. A create_position with our PDA as owner would settle it.
The quote catalogue's token-program split needs re-deriving, not trustingStonkFun's catalogue moves: it was 503 pairs, then 504, and it is 509 today. The classic-SPL count is a property of that day's list, so re-read it with getMultipleAccounts rather than quoting this page.
Meteora's on-chain IDL is staleThe IDL account at the program id is v0.2.0 and disagrees with the deployed bytecode in both directions. Build against the SDK IDL. The three instructions this program needs carry identical discriminators and account order in both.
Bounds B through E for options are off chain onlyA Solana program cannot see greeks or a remote margin engine. Only bound A, the delta-adjusted notional cap, is the existing on-chain notional check. See risk in options.
One endpoint still reads Derive v2 while the rest reads v3/venues/derive/currencies proxies api.lyra.finance, while the equity poller, the coin handler and the status handler read api.derive.xyz/v3. Nobody decided that, and it means a create form offers v2's underlyings for an account that would live on v3.

Fixed since this page was written#

Kept because each diagnosis is worth reading, and because this page asserted all three as current until 2026-09-23. None of them is a blocker any more.

The venue passthrough was far too wide#

Two defects in the same shape, found and fixed on 2026-09-23 and deployed to mainnet the same day. Nothing was ever at risk, because no policy existed while the hole was open.

What was wrongWhat it is now
compound_lp signed with the policy seeds, which authorise both escrows, bounded only by max_in, an argument the caller supplies on a permissionless instruction. An attacker passes u64::MAX.It signs as lp_auth, which owns only lp_quote and lp_base. max_in is gone from the signature rather than ignored, and route moves the LP share into lp_quote so the bound is a balance the program itself put there.
claim_fees forwarded caller-chosen data with the policy signing, so any LaunchLab instruction gated on the creator's signature was reachable, including create_vesting_account.The forwarded data must equal claim_creator_fee's discriminator, not merely start with it. Neither escrow may fall either, which is the new VenueSpentEscrow.

The full shape, including why the two call sites are contained differently, is on the safety model page.

A second leak the fix closed in passing

The LP share used to be left in quote_escrow, which also holds freshly arrived unrouted fees. A compound_lp call before a route therefore pushed the protocol's cut and the bankroll's share into the pool as well, and the keeper's normal path did exactly that.

Real tokenized stocks could not be launched against#

init_policy used to fail with InvalidAccountData for any quote mint carrying a PausableConfig extension, and every xStock sampled has one: SPYX, NVDAX, GOOGLX, QQQX, TSLAX and CRCLX. The pairs the product was designed around were the pairs it could not use.

Quote mint under testBespoke initAssociated token account
Plain Token-2022OKOK
TransferHook onlyOKOK
PausableConfig onlyInvalidAccountDataOK
SPYX, a real xStockInvalidAccountDataOK

Before and after were proven on one validator, with one mint, against the same crate, so the fix is isolated rather than inferred.

The cause was never Anchor and never the account layout. Anchor's codegen for an init token account correctly reads the mint's extensions and sizes the account. The problem was one layer down: the program builds against spl-token-2022 6.0.0, whose extension directory contains neither pausable nor scaled_ui_amount. Both are newer Token-2022 extensions, so the unknown TLV discriminants made the extension read fail and the account was never sized at all.

The fix was to stop doing the sizing locally

All five of the policy's token accounts are now associated token accounts. The on-chain associated token program does its own sizing against the live Token-2022 program, which does know these extensions, so the stale crate is bypassed rather than upgraded and every program-derived address the SDK already knew about for state accounts is untouched.

init_policy has since been proven to succeed against a real cloned SPYX mint, and the test suite went from 17 to 20 passing, 0 failing.

the transaction that proved it
2cs8oYKt3sayMrrZFCutPJZ3vLGHhMqLxZzUUzPA9VYKNBMziKJ17LHb6YWw4Mcj7UUJ4TjXRDq44D5dD39iByeg

Three quote-side accounts cannot all be the policy's own associated token account, since only one can exist per owner and mint, so bankroll and holder_rewards gained their own authority addresses. The full derivations are on accounts and PDAs.

A figure this page previously got wrong

An earlier draft said a SPYX token account requires 478 bytes. Measured on chain it is 179: 165 base, one byte of account type, then ImmutableOwner, TransferHookAccount and PausableAccount. A plain account is 165. A funding table built on 478 would have over-provisioned every launch.

Three further facts read off the live SPYX mint, all of them favourable: TransferHook.programId is the system program, which Token-2022 treats as no hook at all, so transfers need no extra account metas; PausableConfig.paused is false; and DefaultAccountState is Initialized rather than Frozen, so nothing the program creates needs thawing by the issuer.

The claim could not have credited the escrow#

LaunchLab's claim_creator_fee constrains its recipient to exactly ATA(creator, quote_mint). Simulating the claim on mainnet with a deliberately wrong recipient that was a real initialised token account of the right mint returned Anchor error 2015 ConstraintAssociated, so the constraint is enforced and cannot be redirected. While quote_escrow was a bespoke program address the two could never have matched.

The associated token account change fixed this as a side effect: quote_escrow is now ATA(policy, quote_mint) and the policy is the pool's creator, so the addresses agree. One change, two blockers. It does not make the claim useful on its own, because the claim is the wrong mechanism for this launch type in the first place.

Open questions#

These are open by design, not oversights, and the project lists them as such.

  1. Whether StonkFun keeps forwarding. The cadence has now been measured across five real launches, and a measurement of the recent past is not a commitment. Nothing on chain binds them to a share or an interval, and a launch they do not adopt earns nothing.
  2. Whether to build on the older Raydium launchpad type instead. It pays a larger, documented share through a locked position and arrives in both tokens.
  3. When Derive's write endpoints come back. Until they do, an options launch needs a human in a browser per token, which is not a launch flow.
  4. The Hyperliquid agent permission matrix. The probe is written, the account is funded and an agent key exists. It simply has not been run.
  5. A live PDA-owned Meteora position. Inferred, not observed.
  6. Hyperliquid sub-accounts versus vaults for per-strategy isolation, noting that approveAgent carries no sub-account field, so a key is never cryptographically scoped to one.
  7. Who operates the relayer, and at what latency and cost. The mechanism now exists and has carried value once; the operating question is untouched.
  8. Whether buyback_and_burn should burn or distribute. Burning needs no snapshot and is trustless; distribution needs a Merkle snapshot and a claim flow. What is built is the burn.
  9. The five open items in the options risk model: the tenor floor, the delta bands, puts, the inert slider and the 20% in bound C. See risk in options.

How to read the rest of this site#

Anything described in the present tense on another page is implemented in the program and observable either on mainnet or in the API against a local validator. Anything on this page is not. Where a page describes a design that is not built, it says so at that point as well, rather than relying on the reader having found this one.