Program reference

Accounts and PDAs

Five account types, nine named seeds and seven associated token accounts. Everything the protocol enforces is a field on one of these, so this page is also the complete list of what a reader can verify for themselves.

Every seed#

Two kinds of address. The five state accounts are program-derived from named seeds. The seven token accounts are associated token accounts, derived by the associated token program from an owner and a mint, which is what lets them be sized correctly against a real tokenized stock.

AccountDerivationOne per
Config["config"]protocol
Origin["origin", id]origin id (u8)
Model["model", id]model id (u16, little-endian)
Policy["policy", mint]launched token
VenueAccount["venue", policy, token_account]allowlisted destination
bankroll_auth["bankroll_auth", policy]policy, owns the bankroll
holder_auth["holder_auth", policy]policy, owns holder_rewards
fee_key_auth["fee_key_auth", policy]policy, owns fee_key_account
lp_auth["compound_auth", policy]policy, owns lp_quote and lp_base
quote_escrowATA(policy, quote_mint)policy
base_escrowATA(policy, base_mint)policy
bankrollATA(bankroll_auth, quote_mint)policy
holder_rewardsATA(holder_auth, quote_mint)policy
fee_key_accountATA(fee_key_auth, fee_key_mint)policy
lp_quoteATA(lp_auth, quote_mint)policy. Created by route, not at launch
lp_baseATA(lp_auth, base_mint)policy. Created by compound_lp, not at launch

Four separate authorities exist because only one associated token account can exist per owner and mint, and quote_escrow, bankroll, holder_rewards and lp_quote are all in the quote mint. init_policy creates five of the seven token accounts; the two lp_auth accounts are created on first use, with the caller paying, so the launch flow's account list did not have to change. LaunchLab's own pool is at ["pool", base_mint, quote_mint], which is the venue's derivation and not this program's.

quote_escrow being the policy's own ATA is load bearing, twice over

LaunchLab's claim_creator_fee constrains its recipient to exactly ATA(creator, quote_mint), and the policy is the creator. When the escrow was a bespoke PDA the addresses did not match and a claim could never have credited it.

The same address is where StonkFun's forwarding lands, which is the mechanism that actually pays this product. A forwarding transaction creates ATA(creator, quote_mint) if it does not exist, at StonkFun's expense, and transfers into it. That is quote_escrow, so route reads the money with nothing in between.

lp_auth exists because a signature is a blast radius

compound_lp hands the AMM one signature, and whatever it forwards can spend whatever that signer owns. Signing as the policy would have put both escrows in reach, so the compound path got its own authority owning exactly its own staged budget. The two accounts it owns are the entire set a forwarded AMM instruction can debit. Full reasoning on the safety model.

The VenueAccount seeds bind an allowlist entry to both the policy and one exact token account. That is what makes the entry unforgeable: a caller supplying a balance for the equity calculation must supply an entry that derives to the right address, so a token account belonging to somebody else cannot be passed off as deployed capital.

Config#

admin
Pubkey
The only key that may call the four protocol instructions.
pending_admin
Pubkey
Set to the default key at initialize and never read or written again. There is no accept_admin instruction, so there is no two-step handover. The field exists and does nothing.
launchlab_program
Pubkey
The pinned CPI target for claim_fees.
amm_program
Pubkey
The pinned CPI target for compound_lp and buyback_and_burn.
reporter
Pubkey
May attest Remote venue equity. Should not be the agent.
max_remote_staleness
i64
Seconds. How old an attestation may be before the money paths refuse to use it.
max_deviation_bps
u16
How far a remote equity report may move from the previous one before it trips the policy's pause. The report is still recorded.
max_bankroll_bps
u16
The protocol's ceiling on any policy's to_bankroll_bps.
protocol_fee_bps
u16
Taken off claimed quote fees before the deployer's split. Hard-capped at 2000.
protocol_fee_dest
Pubkey
A wallet, not a token account. Every launch pairs a different stock, so the associated token account is derived per call rather than fixed once.
min_risk_for_class
[u8; 8]
The risk a policy must reach before its agent may touch each asset class, indexed by bit position. Written only by initialize. No instruction can ever change it.
paused
bool
The protocol-wide switch. Blocks every money instruction on every policy.

Origin#

id
u8
Also the seed. Permanent.
name
String, max 32 bytes
Not unique. Two origins can share a name and currently two pairs do.
asset_class_mask
u32
A bitwise OR of asset class bits. A venue account outside it cannot be registered. May not be zero.
max_risk
u8
The ceiling on Policy.risk for policies of this origin.

There is no update_origin and no close

create_origin uses Anchor init, so an id can be written once. An origin can never be renamed, re-masked or deleted. A wrong mask is fixed only by adding a new id, and the old one stays visible forever.

Model#

id
u16
Also the seed, little-endian. This is what Policy.model_id refers to.
name
String, max 32 bytes
For example Claude Opus 5.
provider
String, max 24 bytes
For example Anthropic.
enabled
bool
Whether it can be picked at launch. Existing policies are unaffected by it changing.

register_model is init_if_needed, so an id is create-or-overwrite. There is no price, no context window and no capability flags: those change, and the chain is a poor place for something that changes.

Policy#

Identity#

mint
Pubkey
The launched token, and the policy's own seed.
quote_mint
Pubkey
The stock this launch is priced in. Every quote-denominated account on the policy is held in it, and register_venue_account rejects anything else.
fee_key_mint
Pubkey
Recorded at launch and used to size and own fee_key_account. Not part of LaunchLab's actual claim path. See how a launch works.
authority / agent / guardian
Pubkey x 3
The three keys. Only the agent is rotatable, by set_agent.
origin
Pubkey
The origin account, fixed at launch. Every instruction that takes an origin checks it against this field.

The deployer's choices#

mode
Passive | Agent
Written only by init_policy. Nothing can change it.
model_id
u16
Validated against the registry only when the mode is Agent. Meaningless otherwise.
to_lp_bps / to_bankroll_bps
u16
Must sum to 10000. to_bankroll_bps is capped by Config.max_bankroll_bps.
profit_to_lp_bps / profit_to_holders_bps / profit_to_bankroll_bps
u16
Must sum to 10000.
risk
u8
0 to 100, capped by the origin's max_risk.
target_asset
Pubkey
A mint. passive_deploy refuses any venue whose asset_mint is not this exact key.
target_leverage_x
u8
Capped at 5. Unused by the program in options mode, where it is repurposed to select moneyness. See risk in options.
locked / paused
bool
locked is one way. paused can be set by the guardian and cleared only by the authority, and is also set automatically by a deviating attestation.

State and counters#

FieldUnitWritten by
hwmquote base unitssweep_profit
fees_claimedquote base unitsclaim_fees, quote leg only
protocol_feesquote base unitsroute
routed_to_lpquote base unitscompound_lp, by the measured spend
routed_to_bankrollquote base unitsroute
profit_sweptquote base unitssweep_profit, by what physically moved
paid_to_holdersquote base unitsbuyback_and_burn, by the measured quote spent
tokens_burnedbase token unitsbuyback_and_burn and burn_base_leg
credit_spentoff-chain metering unitsnote_credit
venue_countcountregister_venue_account and revoke_venue_account

tokens_burned is the only counter denominated in the launched token rather than the quote, and the two mints typically have different decimals.

venue_count is how the equity calculation stays honest

Every money path that needs equity requires exactly venue_count * 2 remaining accounts, in ascending token-account order with no repeats. Getting that wrong fails with VenueSetIncomplete, so the deployed total can be neither padded nor cherry picked.

VenueAccount#

policy
Pubkey
Checked against the policy on every use, in addition to the PDA derivation.
token_account
Pubkey
For Local, the SPL token account the agent may fund. For Remote, the bridge endpoint funds are sent to on the way out.
kind
Local | Remote
Decides whether equity is read directly or taken from the attestation.
asset_class
u32
Exactly one bit, inside the origin's mask, above the class's minimum risk.
asset_mint
Pubkey
Recorded so a front end can show what the agent is pointed at, and checked by passive_deploy against the target asset.
remote_equity / remote_asof
u64 / i64
Remote only. The attested figure and the venue's own timestamp for it. Meaningless for Local.
bridged_out
u64
Remote only. Cumulative quote sent out, incremented at the moment of transfer, so the gap between sent and claimed is always visible.

revoke_venue_account closes the account and returns the rent to the authority, so a revoked entry leaves no on-chain trace beyond the VenueRevoked event. The indexer keeps a revoked flag so the history survives in the API.

The seven token accounts#

AccountMintWho can debit it
quote_escrowquoteroute only
base_escrowbasebuyback_and_burn, burn_base_leg, by burning only
bankrollquotepassive_deploy, agent_fund_venue, sweep_profit
holder_rewardsquotebuyback_and_burn only
fee_key_accountthe fee key mintnothing. No instruction debits it.
lp_quotequotecompound_lp only, and only through the AMM
lp_basebasecompound_lp only, and only through the AMM

Five of the seven are created by init_policy in a single transaction. The two lp_auth accounts are created on first use instead, lp_quote by route and lp_base by compound_lp, with the caller paying the rent, which is why the launch flow's account list did not change when they were added. All seven are associated token accounts and all use the Token-2022 interface, so the program works against either token program without duplicating its contexts.

Two are owned by the policy itself; the other five are owned by their own authority address, because only one associated token account can exist per owner and mint. Which authority owns an account is not bookkeeping: it is what decides how far a forwarded venue instruction can reach, because a passthrough can spend exactly what its one signer owns.

AccountOwnerSigns with
quote_escrowthe policy["policy", mint]
base_escrowthe policy["policy", mint]
bankrollbankroll_auth["bankroll_auth", policy]
holder_rewardsholder_auth["holder_auth", policy]
fee_key_accountfee_key_auth["fee_key_auth", policy]
lp_quotelp_auth["compound_auth", policy]
lp_baselp_auth["compound_auth", policy]

Enums and bit values#

asset classes, from the program
STABLE   = 1 << 0  =  1
MAJOR    = 1 << 1  =  2
SOL_MEME = 1 << 2  =  4
STOCK    = 1 << 3  =  8
PERP     = 1 << 4  = 16
OPTION   = 1 << 5  = 32
LP       = 1 << 6  = 64
COUNT    = 8       (the array has one unused slot)
EnumVariantsWhere it is fixed
ModePassive, Agentinit_policy, permanently
VenueKindLocal, Remoteregister_venue_account, permanently for that entry

The bit position of an asset class is also its index into Config.min_risk_for_class, which is why register_venue_account computes it with trailing_zeros() after requiring that the class is a power of two.