App & API Architecture - Prototype
1. Summary
This document outlines the pages and API endpoints for the initial prototype of the perpetual futures exchange.
2. App Pages
Navigation Bar
| Element | Description |
|---|
| Logo | Link to home/trade |
| Links | Trade, Portfolio, Vaults, Leaderboard |
| Wallet | Connect wallet / Wallet Dropdown |
Wallet Dropdown
| Option | Description |
|---|
| Accounts | List all trading accounts (primary + sub-accounts) with balance, allow switching |
| Deposit / Withdraw | Quick access to deposit/withdraw margin |
| Transfer | Transfer between trading accounts |
| Disconnect | Disconnect wallet |
3. Pages
Trade Page
Market Stats Bar
Displayed at the top of the trade page for the active market.
| Field | Source |
|---|
| Mark Price | FundingState PDA (oracle-derived) - used for PnL and liquidations |
| Oracle Price | Pyth oracle - raw spot price |
| 24H Change % | Computed from mark price 24h ago vs now |
| 24H Volume | market_stats DB (sum of last 24 hourly buckets) |
| Open Interest | market_stats DB (latest row) |
| Funding Rate | FundingState PDA - current rate and next settlement time |
Components
| Component | Description |
|---|
| Market Selector | Switch between the available markets without navigating away |
| Chart | Candlestick chart built from fill prices (candles table). Displays mark price line overlay |
| Order Book | Live bids and asks from the OrderBook slab via WebSocket |
| Recent Trades | Last fills from trades table via WebSocket |
| Order Form | Place market or limit orders (see below) |
| User Tabs | Open Orders, Positions, Trade History, Funding History |
| Field | Description |
|---|
| Direction | Long / Short |
| Order Type | Market / Limit |
| Leverage | Slider (1x-max market leverage) |
| Size | Position size in USDC |
| Price | Limit price (limit orders only) |
| Preview | Estimated liquidation price, margin required, order value, fees |
The order form calls the API to build an unsigned transaction. The API fetches a fresh Pyth VAA and constructs the place_order instruction. The VAA is required by the on-chain program to validate that the user has sufficient margin at the current mark price - it does not affect the fill price, which is always the best available order book price. The client signs and submits to Solana RPC directly.
User Tabs
| Tab | Source |
|---|
| Open Orders | OrderBook slab on-chain (via WebSocket orders:{wallet}) |
| Positions | Position PDAs on-chain (via WebSocket positions:{wallet}) |
| Trade History | positions_history DB (closed + liquidated positions) |
| Funding History | positions_history.funding_paid DB |
Portfolio Page
| Component | Description |
|---|
| Summary | Total equity, available margin, margin used, unrealized PnL, 30D PnL |
| Positions | All open positions across all markets (from chain) |
| Open Orders | All open limit orders (from chain) |
| Trade History | positions_history - closed and liquidated positions |
| Funding History | positions_history.funding_paid per position |
| Deposits / Withdrawals | account_transactions - deposit, withdrawal, transfer records |
Vaults Page
| Component | Description |
|---|
| Vault List | All active vaults with: name, TVL, share price (NAV), 30D return, performance fee, lockup period |
Vault Detail Page
| Component | Source |
|---|
| Vault Info | Name, description, manager, performance fee, lockup period - from Vault PDA + vaults.description |
| Share Price Chart | vault_stats.nav_per_share over time |
| TVL Chart | vault_stats.tvl over time |
| Open Positions | Position PDAs on-chain for the vault's UserAccount |
| Trade History | positions_history for vault account |
| Transactions | vault_transactions - deposits and withdrawals |
| Deposit / Withdraw | Builds unsigned vault_deposit / vault_withdraw transaction, client signs |
| Vault Activity Log | Admin events (freeze, unfreeze, deprecate) - read from on-chain transaction history |
Leaderboard Page
| Component | Description |
|---|
| Table | Rank, trader address, equity, all-time PnL, realized PnL, volume, trades, funding, win rate, Sharpe, max drawdown |
| Sort | Default by all-time PnL descending. Client-side sort on other columns |
Data source: leaderboard_stats table - precomputed every X minutes by the Indexer.
Faucet Page (devnet only)
| Component | Description |
|---|
| Claim | Request test USDC. One claim per wallet per 24h |
4. API Endpoints
Auth
| Endpoint | Method | Auth | Description |
|---|
/auth/verify | POST | - | Verify wallet signature, receive 24h JWT |
Body: { address, message, signature } - message is a signed timestamp string, signature is base58 tweetnacl ed25519.
Market Data
| Endpoint | Method | Auth | Description |
|---|
/markets | GET | - | List all markets (identity only - symbol, address). Live config (fees, margin %, status) served from Redis/RPC |
/candles | GET | - | OHLCV candles from candles table. Query: symbol, interval, limit, start_at, end_at |
/markets/:symbol/trades | GET | - | Recent fills from trades table |
/markets/:symbol/orderbook | GET | - | Current order book snapshot (from Redis/RPC) |
Orders
| Endpoint | Method | Auth | Description |
|---|
/orders | POST | Bearer | Build unsigned place_order transaction (fetches Pyth VAA, returns serialized tx for client to sign) |
/orders/:id/cancel | POST | Bearer | Build unsigned cancel_order transaction |
/orders | GET | Bearer | Order history from orders_history (filled + canceled). Query: status, market, limit, cursor |
Open orders are not stored in the DB. They come via the orders:{wallet} WebSocket channel.
Positions
| Endpoint | Method | Auth | Description |
|---|
/positions | GET | Bearer | Open positions - read from Position PDAs on-chain (via Redis cache) |
/positions/history | GET | Bearer | Closed + liquidated positions from positions_history DB |
Account
| Endpoint | Method | Auth | Description |
|---|
/accounts | GET | Bearer | List all accounts for the wallet (primary + sub-accounts) |
/accounts | POST | Bearer | Create a new sub-account (DB row only - PDA initialized on first on-chain use) |
/accounts/:id | GET | Bearer | Get account details |
/accounts/:id | PATCH | Bearer | Update account name |
/accounts/deposit | POST | Bearer | Build unsigned deposit_margin transaction |
/accounts/withdraw | POST | Bearer | Build unsigned withdraw_margin transaction |
/accounts/transfer | POST | Bearer | Build unsigned transfer_margin transaction |
/accounts/:id/transactions | GET | Bearer | Deposit/withdrawal/transfer history from account_transactions |
/accounts/:id/snapshots | GET | Bearer | Equity + PnL snapshots from account_snapshots (for portfolio chart) |
Leaderboard
| Endpoint | Method | Auth | Description |
|---|
/leaderboard | GET | - | All rows from leaderboard_stats. Query: sort (column name, default all_time_pnl), order (asc/desc, default desc), search (wallet address prefix). Public |
Vaults
| Endpoint | Method | Auth | Description |
|---|
/vaults | GET | - | List all vaults (identity from DB, live state from Redis/RPC) |
/vaults/:id | GET | - | Vault details |
/vaults/:id/positions | GET | - | Open positions for the vault's account (from chain) |
/vaults/:id/history | GET | - | positions_history for vault account |
/vaults/:id/transactions | GET | - | vault_transactions - deposits and withdrawals |
/vaults/:id/stats | GET | - | vault_stats for TVL + share price chart |
/vaults/:id/deposit | POST | Bearer | Build unsigned vault_deposit transaction |
/vaults/:id/withdraw | POST | Bearer | Build unsigned vault_withdraw transaction |
/vaults/:id/description | PATCH | Bearer | Update vault description (manager only, stored in DB) |
Faucet
| Endpoint | Method | Auth | Description |
|---|
/faucet/claim | POST | Bearer | Airdrop test USDC to wallet. Devnet only. Rate limited per wallet (24h cooldown) |
5. Real-time (WebSocket)
Channels
| Channel | Trigger | Subscriber |
|---|
market:{symbol} | Oracle price update (1s) | Trade page - mark price, oracle price |
candles:{symbol}:{interval} | New fill (candle upsert) | Trade page - chart updates |
orderbook:{symbol} | Order placed / filled / canceled | Trade page - order book |
trades:{symbol} | Fill event | Trade page - recent trades |
account:{id} | Balance change | Wallet dropdown, portfolio |
positions:{wallet} | Position opened / closed / liquidated | User tabs, portfolio |
orders:{wallet} | Order placed / filled / canceled | User tabs |
vault:{id} | Vault TVL / NAV update | Vault list, vault detail |
Page → Channel mapping
| Event | Action |
|---|
| Trade page load | Subscribe market:{symbol}, orderbook:{symbol}, trades:{symbol}, candles:{symbol}:{interval} |
| Switch market | Unsubscribe old market channels, subscribe new |
| Change chart interval | Unsubscribe candles:{old}, subscribe candles:{new} |
| Wallet connected | Subscribe account:{id}, positions:{wallet}, orders:{wallet} |
| Vault detail open | Subscribe vault:{id} |