Skip to main content
Source: programs/pitchmarket/src/lib.rs and interface contract §3–§4. Program ID (pinned in declare_id! and Anchor.toml, deployed on devnet):

Units

Money is integer micro-USDC (1 USDC = 1,000,000). Shares are u64; one share redeems to 1 USDC if its outcome wins. Prices are integers 1..99 (¢).

Accounts (PDAs)

market_id: [u8;32] is a deterministic hash of (match_id, template_key). order_hash = sha256(borsh(Order)) is the primary key for an order everywhere — on-chain, in Postgres, and in the API.

Instructions

The settlement lifecycle — initialize_market, deposit, settle_match, cancel_order, resolve_market, and redeem — is implemented and exercised end to end. The combo instructions are typed stubs returning NotImplemented (see below).

initialize_market(market_id, oracle_tier, resolver_authority)

Creates the Market PDA, both outcome mints (mint authority = the market PDA), and the collateral pool ATA. Called by the backend’s auto market creation, one per template per fixture.

init_vault() / deposit(amount)

init_vault opens the per-user custody PDA (once per user). deposit moves real USDC from the user’s wallet ATA into the vault-owned ATA — the only step where the user signs a live transaction; all trading afterwards is silent, off-chain-signed orders relayed by the operator. Deposit/redeem ATAs are created lazily via init_if_needed.

settle_match(taker, taker_sig, maker, maker_sig, match_type, fill_price, fill_size)

Settles one match from the off-chain engine. One transaction per fill (single taker, single maker). In order it:
  1. Requires the market Unresolved and 1 ≤ fill_price ≤ 99.
  2. Verifies the caller-supplied outcome mints against the market’s pinned yes_mint/no_mint (which applies depends on each order’s outcome field).
  3. Verifies both ed25519 order signatures via instructions-sysvar introspection — see Signed messages for the mandatory transaction layout.
  4. Applies fill accounting to both OrderStatus PDAs: initialized on first touch with remaining = order.size; fails closed with OrderClosed if cancelled or fully filled, OverFill if fill_size > remaining.
  5. Executes the money movement for the match_type:
    • NORMAL — peer-to-peer swap at fill_price,
    • MINT — combines both buyers’ USDC into the pool and mints a complete set,
    • MERGE — burns a complete set, releases pooled collateral to both sellers.
MINT and MERGE move money at each order’s own limit price, not fill_price — only NORMAL uses fill_price. The Go store mirrors this exactly (legDeltaFor).

cancel_order(order_hash)

Signed directly by the maker. Sets is_filled_or_cancelled; if the order was never touched by settle_match, OrderStatus is created fresh so a later fill attempt fails closed with OrderClosed regardless.

resolve_market(outcome) (tier-a only)

Requires oracle_tier == 0 and the signer to equal resolver_authority. Sets the outcome to No (0) / Yes (1) / Void (2) and stamps resolved_at. Tiers (b) challenge-window and (d) TxODDS-signed are designed (ADR 0005) but not implemented.

redeem(outcome, amount)

Requires the market resolved and outcome to be the winning side (any side if Void). Burns amount shares from the caller’s vault-owned outcome ATA and transfers amount × 1_000_000 micro-USDC from the market pool directly to the caller’s wallet ATA, 1:1.

combo_accept(quote, taker_sig) · resolve_combo() — not implemented

Typed stubs returning NotImplemented. The designed semantics (ADR 0004 / interface contract §4): combo_accept verifies the MM’s quote signature, expiry, and QuoteStatus.!spent, pulls the stake from the taker and payout − stake from the MM vault into a ComboEscrow, and marks the quote spent. resolve_combo reads the N leg Market PDAs, computes the AND on-chain, and pays the escrow (VOID leg → refund both). The backend runs combos off-chain behind an interface seam until these land.

Errors you’ll actually see

A build detail worth knowing: the SettleMatch account context is Boxed because it otherwise overflowed the 4 KB BPF stack frame by 64 bytes — a failure that only surfaces at cargo build-sbf, never at cargo check.