Program reference

Instructions

Twenty-one instructions in three groups. Only three of them require a key other than an admin or the policy authority, and none of them can send funds to an address a caller chooses.

Protocol#

Admin only, all four.

InstructionDoesNotes
initializecreates the Config PDAThe only place min_risk_for_class is ever written. Bounds: max_bankroll_bps <= 10000, protocol_fee_bps <= 2000, max_deviation_bps <= 10000, every risk entry at most 100.
set_protocol_paramsupdates the ConfigCan change both pinned program ids, the reporter, the fee destination, the staleness and deviation windows, the bankroll ceiling, the protocol fee and the global pause. Cannot touch min_risk_for_class.
create_origincreates an OriginAnchor init, so ids are permanent. Rejects an empty mask and a max_risk above 100. There is no update and no close.
register_modelcreates or overwrites a ModelAnchor init_if_needed, so calling it again with the same id replaces the entry. This is also how a model is disabled. Name at most 32 bytes, provider at most 24.

Policy#

InstructionWhoDoes
init_policythe deployer, who becomes the authorityCreates the Policy plus five associated token accounts. Fixes the mode forever. Validates both splits, the risk against the origin ceiling, the leverage against the 5x cap, and the model when the mode is Agent. It also verifies the LaunchLab pool: the address, the owning program, the length, the PoolState discriminator and both mints, and then that the pool's creator is this policy.
set_policyauthorityChanges the model, both splits, the risk, the target asset and the leverage. Fails with PolicyLocked once locked. Cannot change the mode.
lock_policyauthorityOne way. Sets locked and there is no instruction that clears it.
set_agentauthorityRotates the agent key. Works after a lock, because a compromised agent key has to be replaceable.
set_pausedguardian or authority to pause, authority only to unpauseThe asymmetry is the whole point of the guardian role.
register_venue_accountauthorityAdds an allowlisted destination. Checks the quote mint, that the class is exactly one known bit, that the bit is in the origin's mask, and that the risk clears min_risk_for_class for it. Works after a lock.
revoke_venue_accountauthorityCloses the entry and refunds the rent to the authority. Decrements venue_count with a saturating subtraction. Works after a lock.

Locking freezes the splits, not the policy

Three of the seven instructions above still work on a locked policy: set_agent, register_venue_account and revoke_venue_account. "Locked" is a statement about where fees go, not about who trades or where they may send funds.

Money#

InstructionWhoDoes
claim_feesanyoneForwards to the pinned LaunchLab program with the policy PDA signing, then credits the measured delta in each escrow. The forwarded data must equal claim_creator_fee's 8 byte discriminator, else NotTheClaimInstruction; neither escrow may fall, else VenueSpentEscrow; and both deltas zero is NothingToDo.
routeanyoneApplies the fee split to the whole quote escrow balance and empties it: the protocol cut, the bankroll share, and the LP share moved into lp_quote. Creates lp_quote and the protocol fee destination's associated token account idempotently, paid for by the caller.
compound_lpanyoneForwards to the pinned AMM program signing as lp_auth and nothing else, then counts the measured drop in lp_quote into routed_to_lp. Takes no max_in: the bound is the balance route put in lp_quote. Creates lp_base idempotently, paid for by the caller.
passive_deployanyonePassive mode only. Moves bankroll funds to the venue account whose asset_mint is the policy's target_asset, within the risk cap.
agent_fund_venueagent onlyAgent mode only. Moves bankroll funds to any registered venue account, within the same risk cap.
report_remote_equityreporter onlyAttests a Remote venue's equity. Rejects a future timestamp beyond the skew window and a notional over 5x equity, and pauses the policy on a deviation beyond the configured band.
sweep_profitanyoneMeasures equity across the bankroll and every venue, splits what is above the high water mark three ways, and raises the mark to what is left. The two destinations are lp_quote and holder_rewards, both paid out of the bankroll with bankroll_auth signing.
buyback_and_burnanyoneSwaps holder_rewards through the pinned AMM if it is non-empty, signing as holder_auth and nothing else, then burns the entire base escrow.
burn_base_leganyoneBurns the base escrow with no AMM involved at all. Exists so a broken swap route cannot block the burn.
note_creditagent onlyAdds to credit_spent. Moves no funds and has no token accounts in its context.

Every instruction in this group refuses to run while either the protocol or the policy is paused, failing with ProtocolPaused or PolicyPaused. The one exception is report_remote_equity, which deliberately still records an attestation on a paused policy, so a real loss can always be written down.

The mode gates#

InstructionRequiresOtherwise
passive_deployMode::PassiveWrongMode
agent_fund_venueMode::AgentWrongMode

No other instruction checks the mode, so claiming, routing, compounding, sweeping and burning behave identically in both.

Why most of it is permissionless#

Seven of the ten money instructions take a caller signer and never check who it is. That is safe because none of them has a destination the caller can choose: every outbound path either goes to a program-derived account, to a destination fixed in the Config, or to a venue account the policy authority registered in advance.

Which means an argument on one of them is the attacker's to choose

compound_lp used to take a max_in that looked like a cap and was not one, because the same caller supplied both the bound and the instruction it bounded. It is gone. On a permissionless instruction, the only real bounds are the ones the program derives for itself, which here means the balance route moved and the single account the passthrough is allowed to sign for. See the safety model.

The practical benefit is that there is no privileged keeper to depend on. If the software normally calling these stops, anybody can call the same instructions and get the same result. The full path analysis is on the safety model.

Events#

Seventeen events, which is what the indexer consumes. Note there is no compound_lp event, so LP compounding has no per-call history on chain.

EventEmitted by
OriginCreatedcreate_origin
ModelRegisteredregister_model
PolicyInitialisedinit_policy
PolicyUpdatedset_policy
PolicyLockedEventlock_policy
AgentRotatedset_agent
PauseSetset_paused
VenueRegisteredregister_venue_account
VenueRevokedrevoke_venue_account
FeesClaimedclaim_fees
Routedroute
PassiveDeployedpassive_deploy
AgentMovedagent_fund_venue
RemoteEquityReportedreport_remote_equity
ProfitSweptsweep_profit
BuybackBurnedbuyback_and_burn and burn_base_leg
CreditNotednote_credit

BuybackBurned is emitted by two instructions

burn_base_leg emits it with spent: 0, since no quote was spent on a swap. An indexer cannot tell the two apart from the event alone except by that zero.

Program constants#

ConstantValueWhat it bounds
BPS10000every split must sum to exactly this
MAX_RISK100the risk slider's upper bound
MAX_LEVERAGE5target_leverage_x wherever it is written
MAX_ASOF_SKEW_SECS120how far a venue timestamp may sit either side of ledger time, in both the report path and the summing path
protocol fee ceiling2000 bpsa literal in initialize and set_protocol_params
attestation leverage multiplier5a literal in report_remote_equity, so no admin can widen it