Skip to main content

Architecture

Technical deep dive into Seesaw's on-chain architecture. This section is for developers building integrations, tooling, or understanding the protocol internals.

System Overview

Account Model

Account Hierarchy

Account Sizes

AccountSize (bytes)Rent (SOL)
Config128~0.001
Market256~0.002
Orderbook8,192~0.059
Vault165~0.002
Position96~0.001

PDA Derivation

All accounts use deterministic Program Derived Addresses:

// Config (singleton)
seeds = ["seesaw", "config"]

// Market
seeds = ["seesaw", "market", market_id.to_le_bytes()]

// Orderbook
seeds = ["seesaw", "orderbook", market.key()]

// Vault
seeds = ["seesaw", "vault", market.key()]

// Position
seeds = ["seesaw", "position", market.key(), user.key()]

Derivation Example

import { PublicKey } from '@solana/web3.js';

const PROGRAM_ID = new PublicKey('Sesaw...');

function deriveMarketPDA(marketId: bigint): [PublicKey, number] {
  const buffer = Buffer.alloc(8);
  buffer.writeBigUInt64LE(marketId);

  return PublicKey.findProgramAddressSync(
    [Buffer.from('seesaw'), Buffer.from('market'), buffer],
    PROGRAM_ID
  );
}

function derivePositionPDA(market: PublicKey, user: PublicKey): [PublicKey, number] {
  return PublicKey.findProgramAddressSync(
    [Buffer.from('seesaw'), Buffer.from('position'), market.toBuffer(), user.toBuffer()],
    PROGRAM_ID
  );
}

Instructions

Instruction Overview

Instruction Details

InstructionSignerKey AccountsDescription
create_marketPayerConfig, Market, Orderbook, VaultInitialize new market
place_orderUserMarket, Orderbook, Position, User TokenSubmit limit order
cancel_orderUserMarket, Orderbook, Position, OrderCancel open order
mint_sharesUserMarket, Vault, Position, User TokenDeposit USDC for shares
snapshot_startCrankMarket, Pyth FeedCapture opening price
snapshot_endCrankMarket, Pyth FeedCapture closing price
resolve_marketCrankMarketDetermine outcome
settle_positionUserMarket, Vault, Position, User TokenClaim winnings
withdraw_sharesUserMarket, Vault, Position, User TokenWithdraw unused shares
close_marketCrankMarket, Orderbook, VaultReclaim rent

State Transitions

Market State Machine

Valid Transitions

Current StateInstructionNext StateConditions
(none)create_marketCREATEDt >= t_start - 24h
CREATEDsnapshot_startTRADINGt >= t_start, Pyth valid
TRADINGplace_orderTRADINGOrder valid
TRADINGcancel_orderTRADINGOrder exists, owner matches
TRADINGsnapshot_endSETTLINGt >= t_end, Pyth valid
SETTLINGresolve_marketRESOLVEDBoth snapshots exist
RESOLVEDsettle_positionRESOLVEDPosition exists
RESOLVEDclose_marketCLOSEDAll positions settled

Error Codes

#[error_code]
pub enum SeesawError {
    #[msg("Market is not in the correct state for this operation")]
    InvalidMarketState,        // 6000

    #[msg("Order price is out of valid range")]
    PriceOutOfRange,           // 6001

    #[msg("Insufficient shares for this operation")]
    InsufficientShares,        // 6002

    #[msg("Insufficient collateral for this operation")]
    InsufficientCollateral,    // 6003

    #[msg("Oracle price timestamp is invalid")]
    InvalidOracleTimestamp,    // 6004

    #[msg("Oracle price is non-positive")]
    InvalidOraclePrice,        // 6005

    #[msg("Oracle confidence exceeds threshold")]
    OracleConfidenceTooHigh,   // 6006

    #[msg("Snapshot already captured")]
    SnapshotAlreadyCaptured,   // 6007

    #[msg("Market not yet resolved")]
    MarketNotResolved,         // 6008

    #[msg("Position already settled")]
    PositionAlreadySettled,    // 6009

    #[msg("Order not found")]
    OrderNotFound,             // 6010

    #[msg("Unauthorized signer")]
    Unauthorized,              // 6011

    #[msg("Arithmetic overflow")]
    MathOverflow,              // 6012
}

Security Model

Access Control

Invariants Enforced

InvariantDescriptionEnforcement
SolvencyVault >= max(yes, no)Checked on every trade
No Crossed BookBest bid < best askMatching engine
No Negative SharesShares >= 0Checked on sell/settle
Immutable SnapshotsOnce set, never changeState check
Deterministic ResolutionSame inputs = same outputPure logic

CPI (Cross-Program Invocation)

Token Transfers

// Transfer USDC from user to vault
token::transfer(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        Transfer {
            from: ctx.accounts.user_token_account.to_account_info(),
            to: ctx.accounts.vault.to_account_info(),
            authority: ctx.accounts.user.to_account_info(),
        },
    ),
    amount,
)?;

Pyth Oracle Read

// Read price from Pyth
let price_feed = &ctx.accounts.pyth_price_feed;
let price_data = price_feed.get_price_unchecked();

require!(
    price_data.publish_time >= boundary_time,
    SeesawError::InvalidOracleTimestamp
);

require!(
    price_data.price > 0,
    SeesawError::InvalidOraclePrice
);

Event Emission

Events for indexers and UIs:

#[event]
pub struct MarketCreated {
    pub market_id: u64,
    pub pyth_feed: Pubkey,
    pub start_time: i64,
    pub end_time: i64,
}

#[event]
pub struct OrderPlaced {
    pub market: Pubkey,
    pub user: Pubkey,
    pub side: OrderSide,
    pub price: u16,
    pub quantity: u64,
    pub order_id: u64,
}

#[event]
pub struct Trade {
    pub market: Pubkey,
    pub maker: Pubkey,
    pub taker: Pubkey,
    pub price: u16,
    pub quantity: u64,
    pub maker_fee: i64,  // Negative = rebate
    pub taker_fee: u64,
}

#[event]
pub struct MarketResolved {
    pub market: Pubkey,
    pub outcome: Outcome,
    pub start_price: i64,
    pub end_price: i64,
}

Related Documentation