Market 0 · Solana devnet

MarketZero

Devnet market for Dark Percolator, created 2026-11-11. One public market, one native-SOL vault, one hedge ticket, and one keeper escrow. No portfolio has been opened. The market is still on the base layer.

What is new about it

Public aggregates.
Private everything else.

A normal perp publishes the book, the position, and the liquidation price. This market splits those. The mark, open interest, insurance, and fees are a public account anyone can read. Each trader's position, collateral, and intent live in a portfolio that is delegated into a MagicBlock Private Ephemeral Rollup on Intel TDX. The rollup serves that account only to the trader, the keeper, and at most two auditors the trader names.

There is no order book and no slab. A trader submits one intent. The keeper crosses up to 16 portfolios in one call. Every fill happens at the same mark. Buys take sells. With pool_cap at 0 the pool takes no inventory, so a batch fills only what both sides brought. Unfilled size stays open for the next batch.

Time in this market is rollup time. A rollup slot on this devnet validator was measured at 9.956 ms (1,133 slots in 11,280 ms). The bounty4 figures of 150 slots and 6,480,000 slots assume a 400 ms base-layer slot, which would be a 60 second mark and a 30 day EWMA half-life. Those same wall-clock targets were converted onto the measured rollup clock and then written into the market. Nothing in the program can change them.

Collateral is native SOL in one vault. The vault is owned by the Dark Percolator program and is never delegated, so the private rollup cannot move the lamports. Insurance sits in that same vault. The program has no instruction that pays insurance or pool lamports back out.

The hedge is a ticket, not an order. commit_market on the rollup schedules record_hedge. That instruction accepts only the keeper's escrow PDA as signer, which only the MagicBlock program can produce, and it writes the pool's inventory onto the hedge ticket. An operator reads the ticket and places any Phoenix hedge from their own wallet.

The mark is a push from the oracle key, bounded by a solvency envelope. The first push may set any positive price. Later pushes may move the mark by at most max_move_bps_per_slot times the rollup slots elapsed. When the oracle reports the price as stale, the EWMA walks toward the indicative price and the trading fee rises with the gap between the EWMA and its reference.

Addresses

The accounts on chain.

Cluster: devnet (https://api.devnet.solana.com). Program Cf8dRz9xhvdwU825LBu6SGHa3gcHMiJwVh8LciJK1hPz, executable, upgradeable loader. Authority, oracle, and keeper are the same key.

AccountAddressOwnerLamportsData
Market64kBzfr4wFLLiNBAh5iZ1xQLsEpFvAmqETFArkUKSccNDark Percolator2,230,120311 bytes
VaultCZXGH62x18zkpbzthFPAdB5tS9dxeML1zwUp191AFGz3Dark Percolator50,853,44040 bytes
Hedge ticketJ9Af88NzfUJ6GazSDHwSBB7rBRgJnnazcPwTmRW7NZkLDark Percolator1,183,640105 bytes
Keeper escrow, index 255Eb4b35WtV64d6gjaEvpHHxfMwhry6NeCTtyyUtYstaXKSystem program850,2400 bytes
Seeds

How the PDAs are derived.

AccountProgramSeedsBump
MarketDark Percolator["market", authority, id_le_u64] with id 0254
VaultDark Percolator["vault", market]253
Hedge ticketDark Percolator["hedge", market]252
EscrowDELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh["balance", keeper, 255]254

A future portfolio is ["portfolio", market, trader] under Dark Percolator. Its permission account is ["permission:", portfolio] under ACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1. Neither exists yet.

Related programs

What the market instructions name.

System
11111111111111111111111111111111
Magic
Magic11111111111111111111111111111111111111
Magic context
MagicContext1111111111111111111111111111111
Parameters, frozen at init

Written once.
Nothing in the program can change them.

Meanings below use the measured 9.956 ms rollup slot.

FieldValueMeaning at 9.956 ms/slot
mm_bps5005% maintenance margin
im_bps5005% initial margin
base_fee_bps11 bp when the oracle is fresh
max_fee_bps10,000fee can rise to 100% of notional while the oracle is stale
liq_fee_bps55 bp liquidation fee
liq_fee_cap50,000,000,00050 SOL cap on that fee
max_move_bps_per_slot1about 100 bp per second of mark movement
max_mark_age_slots6,027about 60.0 seconds, then trading stops
ewma_halflife_slots260,348,936about 30.0 days
pool_cap0a batch takes no pool inventory

max_move_bps_per_slot is an integer. The 49 bp-per-400 ms bounty4 envelope is 122.5 bp per second. One basis point per rollup slot is the closest integer, about 100 bp per second.

Margin is symmetric: initial equals maintenance, and initial is not allowed below maintenance. A new intent enters the batch only when a full fill would still clear initial margin. A reduce that does not flip the position enters anyway. Liquidation runs when equity is under maintenance and hands the closed size to the pool. pool_cap does not apply to that handoff. Pool collateral is 0, so a liquidation that leaves the pool unable to carry the position becomes bad debt, and insurance pays that first.

What the accounts hold right now

Read back after creation.

Market 64kBzfr4wFLLiNBAh5iZ1xQLsEpFvAmqETFArkUKSccN.

oracle
same key
keeper
same key
id
0
bump / vault_bump
254 / 253
mark_e6
0
mark_slot
0
oracle_stale
false
ewma_e6 / ewma_ref_e6 / ewma_slot
0 / 0 / 0
oi_long / oi_short
0 / 0
pool size / entry_e6 / collateral
0 / 0 / 0
insurance
50,000,000 lamports (0.05 SOL)
fees_collected
0
uncovered_bad_debt
0
batch_seq / commit_seq
0 / 0

Vault CZXGH62x18zkpbzthFPAdB5tS9dxeML1zwUp191AFGz3 stores the market pubkey and the lamports. Of its 50,853,440 lamports, 50,000,000 are the insurance balance recorded on the market and 853,440 are the vault's own rent. Traders will deposit into this same account. Their claim is the collateral field on their portfolio, not a separate token account.

Hedge ticket J9Af88NzfUJ6GazSDHwSBB7rBRgJnnazcPwTmRW7NZkL stores the market pubkey, the keeper pubkey, and bump 252. Sequence, pool size, mark, and recorded slot are 0 until the first record_hedge.

Escrow Eb4b35WtV64d6gjaEvpHHxfMwhry6NeCTtyyUtYstaXK is an empty system account. Devnet rent for a 0-byte account is 650,240 lamports. The top-up added 200,000 lamports on top of that, so the account holds 850,240. record_hedge accepts this PDA, at index 255, as its only signer. The index is fixed by ActionArgs in the Magic program and by the Dark Percolator check. A top-up at index 0 would not satisfy it.

Transactions

Both are finalized,
error null.

StepSignatureSlot
init_market and fund (insurance, not pool)577FwMsf5hHqazQqrVrScbuzruVSk3cx4GkZcXnzRLkiaoTfd6i2HWvPGh8Uo4ksmz6qqrLPeatzg5u3CepDp33K521249243
Escrow top-up, index 255, 200,000 lamports5p3fgDtEc4YrGV29RDJ4J94EopEBRF1az6KV86M55ogk1hCbRUCUUWLLkkJm5Kdh6ToytPfdtbbaZTPxBQruUEe2521249245

The payer EJXjqJ51JCncsNN5mM8DXjw34d85fm5zgSwoQckghhq5 went from 1.662602132 SOL to 1.607474692 SOL. The 55,127,440 lamports break down as:

UseLamports
Market rent2,230,120
Vault rent853,440
Insurance, locked50,000,000
Hedge-ticket rent1,183,640
Escrow rent650,240
Escrow top-up200,000
Two base fees10,000
Total55,127,440
How a later trade would move

Base layer, then the rollup.

Base layer, public

Base

open_portfolio creates the trader's portfolio and pre-funds the rent its permission account will need.

Base

deposit moves SOL into the vault and adds the same amount to that portfolio's collateral.

Base

delegate_portfolio and delegate_market hand those accounts to MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo.

Rollup, inside the TEE

The RPC is https://devnet-tee.magicblock.app with a MagicBlock session token from verifyTeeRpcIntegrity and getAuthToken. The token is a signed challenge, not a dashboard key.

Rollup

init_permission, then set_privacy(true, auditors). Members are the trader, the keeper, and up to two auditors. The keeper is a member of every portfolio so it can cross and liquidate.

Rollup

push_mark(price_e6, fresh) from the oracle key.

Rollup

submit_intent stores one intent and the SHA-256 of its v2 encoding. The portfolio must already be private.

Rollup

cross_batch fills at the mark, up to 16 portfolios.

Rollup

liquidate closes a portfolio that is under maintenance.

Rollup → Base

commit_market commits the public market and schedules record_hedge. The keeper escrow pays that action from the 200,000 lamport top-up.

Back on the base layer, withdraw pays collateral out only when the portfolio is undelegated, flat, and has no open intent.

Limits that are part of this market's shape: one open intent per portfolio, at most 16 portfolios in a batch, at most two auditors, and a batch that cannot take inventory. The mark is whatever the oracle key pushes inside the envelope. Deposits and the market account are public. The private part is the delegated portfolio.

Program flow and the build are in dark-percolator.md.

Tap anywhere to start the anthem
A steaming metal percolator
PercolatorAnthem
0:00
4:11
copied