Venues
The table that matters#
| Venue | What for | Chain | Custody | Equity |
|---|---|---|---|---|
| Raydium LaunchLab | the launch itself and fee accrual | Solana | Policy PDA is the pool creator, and StonkFun forwards the creator share to it | n/a |
| Meteora DAMM v2 | LP compounding and the buyback | Solana | Policy PDA owns the position | Local, read directly |
| Hyperliquid | perpetuals | its own L1 | master account holds funds, an agent wallet trades | Remote, attested |
| Derive | options pricing | an OP Stack L2 | none: the vault holds its quote asset on Solana and reads a public book | Local, on chain |
The Solana legs#
Two program ids are pinned in Config, each for different instructions, and the passthrough guard checks the CPI target against the right one before signing.
| Pinned as | Program | Used by |
|---|---|---|
launchlab_program | LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj | claim_fees |
amm_program | cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG | compound_lp and buyback_and_burn |
Meteora DAMM v2 was measured live at roughly 6,667 transactions per minute on 2026-09-22.
A Local venue account is an ordinary SPL token account. Its equity is its balance, read directly from the chain, trusting nobody. That is the current implementation and it stays that way for the Solana leg.
Both halves of that have since been checked rather than assumed. Raydium's lock program publishes exactly four instructions, none of which increases an existing lock, and lockCpLiquidity mints a fresh fee NFT per call. It is moot for StonkFun anyway: with creator_scale = 0 the creator is handed no locked position at all at migration. On the Meteora side, create_position and add_liquidity are separate repeatable instructions, and a simulated add_liquidity against a pre-existing funded position was accepted and carried to the token transfer.
Hyperliquid, for perpetuals#
Measured live on 2026-09-22 from api.hyperliquid.xyz/info:
| Measure | Value |
|---|---|
| Markets | 234 |
| Open interest | $14.08B |
| 24h volume | $7.75B |
| BTC open interest | $4.03B |
| BTC 24h volume | $3.32B |
Why not a Solana perp venue#
Because measurably nobody is using them. On the same day, newest program activity on Solana mainnet was:
| Venue | Most recent activity |
|---|---|
| Drift v2 | 2.7 days ago |
| Zeta | 1.7 days ago |
| Mango v4 | 6.9 days ago |
| Adrena | 8 hours ago, at 0.1 transactions per minute |
| Raydium CLMM (control) | 1,000 signatures inside 1 second |
The control exists to show the measurement method works: a busy Solana program looks nothing like the four above.
The Solana perp venues are deployed and effectively unused. Lighter was the alternative and loses on two counts: its only trade-but-not-withdraw key class is maker-only (post-only, ALO, cancel), which forbids the taker orders a directional strategy needs, and its Robinhood-domain instance excludes the US, the UK and Canada.
Sub-accounts, not vaults#
Sub-accounts are createable and fundable through documented actions (createSubAccount, subAccountTransfer). Vaults have no createVault action in the SDK at all: creation is a web-app-only human step, which breaks the permissionless keeper model, and vaults add a leader profit share and a deposit lockup that are irrelevant to a single-owner bankroll.
One consequence worth knowing: approveAgent carries no sub-account field, so per-strategy isolation comes from which sub-account gets funded, not from the venue scoping the key.
The first real crossing, and the order that followed it#
Both happened on 2026-09-23, and they are the two things this leg had never done before.
| Step | What actually happened |
|---|---|
| The deposit | A plain ERC-20 transfer of 20 real USDC on Arbitrum One into Hyperliquid's bridge, Arbitrum transaction 0x39fde3ab57935b381afbce748e16036253b0d36ade7631542c7f1724844fede9. The bridge credits whoever sent, so the sender and the Hyperliquid account are the same address. |
| Where it landed | Read back immediately afterwards: clearinghouseState showed accountValue 20.0, withdrawable 20.0 and no positions, while spotClearinghouseState showed no balances at all. The deposit went straight to the perp account. |
| The agent key | approveAgent succeeded against that account under the name bankroll. That is itself evidence the credit had landed, because Hyperliquid refuses every action from an account that has never been funded. |
| The order | Signed by the agent key, not the master: leverage set to 5x cross on SOL, then FILLED at oid 554650877349, size 0.1 at 114.71. Read back as one position with $11.47 of position value and $2.294 of margin used against $19.99 of account value. |
So the signing implementation is correct against the real mainnet exchange rather than only against the vendor's 26 published test vectors, and an approved agent can open a leveraged position on the master's account without the master signing anything.
Can a Hyperliquid agent key withdraw? Unverified#
if exchange.account_address != exchange.wallet.address:
raise Exception("Agents do not have permission to perform internal transfers")What is not confirmed is the server-side authorization matrix. Hyperliquid's validator source is closed, so this rests on the vendor saying so twice, not on inspectable enforcement. Worse, whether subAccountTransfer and vaultTransfer specifically are agent-blocked is stated nowhere; only usdSend carries an explicit guard.
What has been proven on Hyperliquid#
| Claim | Status |
|---|---|
| Signing is correct | 26 of 26 vendor test vectors reproduced offline, live calls to the real testnet exchange echoing back exactly our master address, and now a filled order on the real mainnet exchange. |
| Value can cross to the venue | Proven on mainnet 2026-09-23: 20 USDC from Arbitrum One landed in the perp account. The crossing is operator-run, not trustless. |
| An approved agent key can trade the master's account | Proven. A 5x cross SOL position was opened by the agent key, and the master signed nothing. |
| Equity attestation works end to end | Real readings posted to chain, including $3,097,182.04 read from a public HLP address, with a later cycle posting a different figure, so it is live rather than cached. |
| The staleness and deviation rails hold | Provoked rather than assumed: 8 of 8, including that a 30% move is recorded and also pauses the policy, so a deviating report never hides the loss. |
| An approved agent key cannot withdraw | Unverified. The probe is written and has never been run. Not evidence that it can; not evidence that it cannot. |
Derive, for options#
Options are priced against Derive, and the thing worth understanding first is that the vault does not send money there. An options policy holds its quote asset in the bankroll on Solana. Derive supplies the market: which contracts exist, what they are bid and offered at, their mark, their delta and their implied volatility.
That is a smaller dependency than it sounds, and a deliberate one. Reading a book needs no account, no subaccount, no deposit, no bridge and no key. It is a public endpoint. So an options launch has nothing to provision and nothing to trust a venue with, and the failure mode of the venue being unreachable is a price that cannot be read rather than money that cannot be recovered.
deployer picks underlying + call or put -> risk number picks moneyness + tenor Derive's live instrument list -> the contract that exists nearest that mandate Derive's live quote -> what the vault's holdings come to at the offer
What is read, and from where#
Two public calls, neither of which is authenticated. public/get_instruments lists what is live, which is how a contract is resolved rather than assumed: there is no point naming a strike that Derive does not list. public/get_ticker gives the quote for one instrument, carrying Derive's own timestamp so a stale read is visible as a stale read.
The options risk rules#
Leverage on an option is not the premium ratio, it is the delta. A far out-of-the-money call bought with 1% of capital can carry more directional exposure than a 5x perpetual, so capping premium spent would not catch it. Two rules, both required, chosen so an options position can never do something a 5x perp could not:
| Rule | What it means |
|---|---|
| Defined risk only | Max loss must be bounded and known at entry: long options, debit spreads, and credit spreads whose width is fully collateralised. No naked short options, ever, at any risk setting. A naked short has unbounded loss, which no leverage cap expresses. |
| Delta-adjusted notional at most 5x | |net_delta| * underlying_price <= 5 * allocated_capital |
Those two rules are the headline. The full set is five bounds, A through E, and there is a separate question they do not answer: what the deployer's 0 to 100 risk slider actually governs once the venue is options, given that for a long option the premium paid is the maximum loss. That has its own page: risk in options.
Registering a venue account#
A venue account is an allowlist entry created by register_venue_account, which only the policy authority can call. It records the token account, the kind (Local or Remote), exactly one asset class bit and the asset mint. Four checks have to pass:
- The token account must be held in the policy's own
quote_mint, elseWrongMint. asset_classmust be exactly one known bit, elseBadAssetClass.- That bit must be inside the origin's mask, else
AssetClassNotInOrigin. - The policy's risk must be at least
Config.min_risk_for_class[bit], elseRiskBelowAssetClass.
Venue liveness, live#
/status reports each venue's reachability. The two Solana programs are checked with getAccountInfo; the two remote venues are reported by their pollers, and say so explicitly when they have not been polled.
"venues": {
"launchlab": {
"reachable": true,
"programId": "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj",
"source": "chain:getAccountInfo"
},
"meteoraDammV2": {
"reachable": true,
"programId": "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG",
"source": "chain:getAccountInfo"
},
"hyperliquid": { "value": null, "source": "venue poller", "absent": true, "reason": "not polled yet" },
"derive": { "value": null, "source": "venue poller", "absent": true, "reason": "not polled yet" }
}A venue that has not been polled returns absent: true with a reason rather than a zero or a false. That distinction runs through the whole API and is described on the API overview.