Appearance
Accounts and transactions
Program ID: 9zA7Ctc39vg8tbUezeiVHfNotnt4SLAgY8oX9VXkciCw (current deployment; mainnet: TBD). Integer seeds are little-endian (u64 = 8 bytes, u8 = 1 byte).
Accounts
| Account | Seeds | Holds | Created by / rent paid by | Closed |
|---|---|---|---|---|
Config | ["config"] | Parameters, roles, house (LP) balances, payout-queue head and tail, staking pool | initialize | Never |
| Vault | ["vault"] | All USDC (an SPL token account owned by Config) | initialize | Never |
Market | ["market", index: u8] | Market parameters, open interest, OI limits and brake, oracle watermark, settlement pin (settle_pin_ts) and settlement price | Pre-launch setup or an AddMarket proposal | Never |
Trader | ["trader", owner] | Available, locked and queued USDC; $NOTE unstaked/staked; reward accounting; session key; counters (next_request, the next request id; next_position, a count of positions ever opened) | create_trader (owner, ≈ 0.0022 SOL) | Never |
Request | ["request", owner, id: u64], where id is the trader's next_request | A pending open or close: pin, expiry, escrowed SOL, and the admissibility limits in force when it was made (max_conf_bps, max_ema_dev_bps), which its fill or void uses. Zero means a request made before these were recorded, which uses the live limits. | Request signer (≈ 0.0019 SOL + execution fee + escrowed rent) | At fill, cancel or void; rent goes to the signer |
Position | ["position", owner, id: u64], where id is the id of the open request that created it | Side, entry, margin, leverage, notional, entry publish time, pending-close marker | Filler at execute_open, reimbursed from the request's escrow | At close, liquidation or settlement; rent goes to the open request's signer |
QueueClaim | ["claim", owner, position_id: u64], where position_id is the id of the position whose win queued | An unpaid win: queue index (its FIFO position), owner, position id, amount | When a win queues: a close filler, reimbursed from the close request's escrow; or a retired-market settler, who is not reimbursed until the claim is fully paid | When fully paid; rent goes to the close request's signer (or the settler) |
Proposal | ["proposal", id: u64] | A timelocked governance action | Admin | Never (status changes) |
Trader instructions
| Instruction | Signer | What it does | Typical failures |
|---|---|---|---|
create_trader | Owner | Creates your trading account | Already exists |
deposit(amount) | Owner | USDC from your token account to the vault; credits available | NotLaunched, InvalidParam |
withdraw(amount) | Owner | USDC from the vault to any USDC token account (except the vault); debits available | InsufficientBalance, BadDestination |
set_session(key, expires_ts) | Owner | Delegates trading to key until expires_ts (≤ 30 days ahead); replaces any previous key | InvalidParam |
revoke_session | Owner | Removes the session key | — |
request_open(is_long, margin, leverage, max_samples) | Owner or session key | Locks margin, reserves OI and notional, creates a request with its pin, escrows execution fee and position rent | See How trading works |
request_close(max_samples) | Owner or session key | Creates a close request for one position, marks the position as closing, escrows execution fee and claim rent | ClosePending, MarketSettled, SettlementPending, StaleHeartbeat, ClockLag |
cancel_request | Anyone, only after expiry | Open: refunds locked margin and releases reservations. Close: clears the closing marker, and the position stays open. ¼ of the execution fee goes to the caller; the rest of the escrow goes back to the request's signer. | RequestNotExpired (at or before expiry) |
stake(amount), unstake(amount) | Owner or session key | Moves $NOTE between unstaked and staked (instant) | InvalidParam |
claim_rewards | Owner or session key | Credits accrued USDC rewards to available | — |
max_samples is the most price samples you accept. Production always uses 1, so any value works.
Permissionless instructions
| Instruction | Signer | What it does |
|---|---|---|
execute_open | Anyone | Fills an open at its pinned update and creates the position. The filler pays the position rent and is reimbursed. The execution fee goes to the update's poster. |
execute_close | Anyone | Fills a close at its pinned update and settles PnL; creates a queue claim if the win queues. A close pinned before its market's settlement pin still fills, even after settlement. |
liquidate | Anyone | Liquidates a bust position at a fresh verified price (Liquidation). Takes no queue-claim account: liquidations never queue. |
void_close(sample) | Anyone | Cancels a close whose pinned update is authentic but inadmissible |
settle_retired | Anyone | Closes a position in a settled market at its final price; refuses a position with a pending close (ClosePending) until that close is filled, voided, or expired and cancelled. The Papersol keeper does this automatically, and the app has a Settle button. |
observe_price | Anyone (fee payer only) | Records a fresh verified price as the market's oracle watermark (heartbeat) |
harvest, harvest_one | Anyone | Pays the payout queue from the front, fully or in part |
sweep | Anyone (fee payer only) | Moves treasury above staker_cap to stakers and pushes pending staker revenue into streaming |
execute_proposal, execute_add_market | Anyone, after eta and within 7 days | Applies a timelocked proposal. SettleMarket: only after the settlement pin + 120 s, with the Pyth update pinned at it; without one (dead feed), only the admin, 24 h after the pin. A SetMarket that re-opens a market with a settlement pin succeeds only while both the Solana clock and the market's last_oracle_ts are more than 1 h before its pin, or after the settlement lapses (more than 7 days after the pin). The Papersol keeper executes due settlements. |
migrate_market, migrate_request | Anyone (pays the extra rent) | Zero-extends a Market created before settle_pin_ts was added, or a Request (open or close) created before its admissibility limits were added. The new bytes are zero (no settlement pin; live admissibility limits), so behaviour doesn't change. |
Role-gated instructions
| Instruction | Signer | When |
|---|---|---|
initialize | Program upgrade authority | Once |
setup_params, setup_market | Admin | Before launch only |
launch | Admin | Once; irreversible |
propose | Admin | After launch. SettleMarket records the proposal's eta as the market's settlement pin (one pending settlement per market) and snapshots the admissibility limits. |
cancel_proposal | Admin or guardian | While pending. A settlement proposal can be cancelled (or its market re-opened) only while both the Solana clock and the market's last_oracle_ts are more than 1 h before its pin, or after the settlement lapses (more than 7 days after the pin); cancelling it clears the settlement pin. |
set_paused | Guardian or admin to pause; admin only to unpause | Any time |
set_oi_brake | Admin; guardian may only lower | Any time |
set_oi_limits | Risk keeper | Any time, within [usage, ceiling] |
accept_admin | Pending admin | After a SetAdmin proposal |
claim_dev_fees(amount) | Admin | Up to accrued dev fees |
set_mock_price | Admin | Test builds only; production builds reject it |
Events
| Event | Emitted by |
|---|---|
CashFlow { kind } | Deposit (0), withdrawal (1), reward claim (2) |
RequestCreated | Open and close requests (pin, expiry, samples) |
RequestCancelled | Cancel and void |
PositionOpened | Open fills (entry, entry publish time, margin, leverage, notional) |
PositionClosed { kind } | Loss (0), win (1), liquidation (2), retired settlement (3), with raw PnL, haircut win, returned, queued, fee, $NOTE minted |
ClaimHarvested | Each queue payment (paid, payout, remaining) |
StakeChanged | Stake and unstake |
LpSettled | Sweeps and staker revenue distribution |
OiLimitsChanged, OiBrakeChanged, ControlsChanged, ProposalEvent | Risk and governance actions |