A high-performance decentralized perpetual futures exchange built on Solana, implementing a complete on-chain trading architecture with slab-based orderbook, matching engine, margin system, and liquidation mechanisms.
PerDEX is a fully decentralized perpetual futures exchange (DEX) on Solana that enables traders to open leveraged long and short positions on crypto assets without centralized custody or intermediaries. Built with Rust and Anchor framework, it implements the complete infrastructure needed for a production-grade perpetual DEX, following Serum's CLOB architecture and Solana's account model.
- Non-Custodial: Users maintain full control of their funds at all times
- Transparent: All trades, liquidations, and settlements occur on-chain
- Permissionless: Anyone can trade without KYC or geographic restrictions
- Censorship-Resistant: No single entity can halt trading or freeze accounts
- Trustless: Smart contracts enforce all rules deterministically
- On-Chain Orderbook: Complete CLOB implementation living on Solana
- Deterministic Execution: All operations produce consistent, reproducible results
- Solana-Optimized: Leverages PDAs, zero-copy deserialization, and parallel transaction processing
- Capital Efficient: Cross-margining and portfolio-level risk management
- Production-Ready: Request/event queue pipeline for scalable order processing
The on-chain orderbook implements a Serum-inspired slab structure:
- On-Chain State: Entire orderbook stored in Solana account data
- B-Tree Arena Storage: Nodes stored contiguously for efficient on-chain access
- O(log n) Operations: Efficient insert, delete, and price discovery within compute budget
- Price-Time Priority: Deterministic matching order enforced by blockchain
- Zero-Copy Access: Direct memory mapping for gas-efficient operations
#[account(zero_copy)]
pub struct OrderbookSlab {
pub nodes: [SlabNode; MAX_NODES],
pub free_list_head: Option<u32>,
pub root: Option<u32>,
pub bid_best: Option<u32>,
pub ask_best: Option<u32>,
}Decentralized order processing following Solana's compute model:
User Transaction β Request Queue (PDA) β Cranker (Permissionless) β Matching Engine β Event Queue (PDA) β Settlement
- Request Queue: On-chain buffer for incoming order instructions
- Permissionless Cranking: Anyone can call the crank instruction for rewards
- Compute-Aware Batching: Processes multiple orders within transaction limits
- Event Queue: On-chain log of fills and cancellations for indexers
- Deterministic Processing: Blockchain consensus ensures reproducibility
Full-featured matching engine implemented in Anchor program:
- LIMIT: Price-specified orders with post-only, IOC, FOK options
- MARKET: Execute immediately at best available on-chain price
- STOP-LIMIT: Triggered orders (optional, via oracle integration)
- Price-time priority execution enforced on-chain
- Partial fill support with state tracking
- Maker/taker fee differentiation
- Self-trade prevention (same owner check)
- Cross-program composability
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub enum OrderType {
Limit { price: u64, post_only: bool },
Market,
}
#[account]
pub struct Order {
pub owner: Pubkey,
pub order_id: u128,
pub side: Side,
pub order_type: OrderType,
pub size: u64,
pub filled: u64,
pub timestamp: i64,
}On-chain risk management without trusted intermediaries:
- Long/short position tracking in program-derived accounts
- Entry price calculation on-chain (FIFO, weighted average)
- Unrealized PnL based on oracle price feeds (Pyth/Switchboard)
- Realized PnL on position closure
- Initial Margin (IM): Collateral required to open positions
- Maintenance Margin (MM): Minimum collateral to avoid liquidation
- Cross-Margin: Shared collateral across all positions
- Portfolio Margining: Net position risk calculation
#[account]
pub struct UserPosition {
pub owner: Pubkey,
pub market: Pubkey,
pub size: i64, // Positive = long, negative = short
pub entry_price: u64,
pub collateral: u64, // Posted collateral
pub unrealized_pnl: i64,
pub realized_pnl: i64,
pub last_funding_index: u64,
pub bump: u8,
}Permissionless liquidation mechanism:
- Oracle-Based Monitoring: Uses Pyth/Switchboard price feeds for mark price
- Liquidation Triggers: Any user can call liquidate instruction when conditions met
- Liquidator Incentives: Liquidators earn portion of liquidation penalty
- Insurance Fund: On-chain PDA accumulating penalties and covering losses
- Backstop Mechanism: Protocol-level protection against cascading liquidations
pub fn liquidate(ctx: Context<Liquidate>) -> Result<()> {
let position = &mut ctx.accounts.position;
let oracle_price = ctx.accounts.oracle.get_price()?;
require!(
position.margin_ratio(oracle_price) < MAINTENANCE_MARGIN_RATIO,
ErrorCode::PositionNotLiquidatable
);
// Transfer liquidation penalty to liquidator and insurance fund
// Close position at oracle price
// Emit liquidation event
}Decentralized account management:
- SPL token vault accounts for collateral (USDC, SOL, etc.)
- Atomic trade settlement via CPI to token program
- Fee collection to protocol treasury PDA
- Funding payment processing every 8 hours
- Withdrawal permissions enforced by margin checks
Built for on-chain performance:
- Anchor Framework: Type-safe program development with automatic account validation
- Zero-Copy Deserialization: Direct account data access without deserialization cost
- Parallel Transaction Processing: Independent accounts enable concurrent execution
- Compute-Optimized: Batched operations to maximize compute units
- Account Layout: Strategic use of PDAs for deterministic addressing
perdex/
βββ programs/
β βββ perdex/
β βββ src/
β βββ lib.rs # Program entry & instruction handlers
β βββ state/ # Account structures
β β βββ orderbook.rs # Orderbook slab state
β β βββ position.rs # User position accounts
β β βββ market.rs # Market configuration
β β βββ queues.rs # Request/event queues
β β
β βββ instructions/ # Instruction handlers
β β βββ initialize.rs # Market initialization
β β βββ place_order.rs # Submit orders
β β βββ cancel_order.rs # Cancel orders
β β βββ crank.rs # Process request queue
β β βββ settle.rs # Settle trades
β β βββ liquidate.rs # Liquidation logic
β β
β βββ engine/ # Core matching logic
β β βββ matcher.rs # Order matching algorithm
β β βββ slab.rs # Slab operations
β β
β βββ margin/ # Risk calculations
β β βββ calculator.rs
β β βββ oracle.rs # Price feed integration
β β
β βββ errors.rs # Custom error codes
β
βββ app/ # Frontend (React + Wallet adapters)
βββ tests/ # Anchor integration tests
βββ scripts/ # Deployment & setup scripts
βββ Anchor.toml # Anchor configuration
βββ Cargo.toml
βββ README.md
ββββββββββββββββββββ
β User's Wallet β
β Signs TX β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Place Order IX βββββ Anchor instruction
β (On-Chain) β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Request Queue βββββ PDA account stores pending orders
β (PDA) β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Crank IX βββββ Anyone can call (permissionless)
β (Keeper/User) β Earns crank fee
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Matching Engine βββββ Executes on-chain
β (Smart Contract) β Updates orderbook slab
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Event Queue βββββ PDA stores fill events
β (PDA) β Consumed by indexers
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Position Update βββββ Updates user position PDA
β (PDA) β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Oracle Check βββββ Pyth/Switchboard for mark price
β (Pyth/Switch) β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β Liquidation IX βββββ If underwater (permissionless)
β (Anyone) β Liquidator earns reward
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β SPL Token CPI βββββ Atomic settlement
β (Settlement) β
ββββββββββββββββββββ
// Market PDA
[b"market", market_index.to_le_bytes()]
// User Position PDA
[b"position", user.key(), market.key()]
// Orderbook Slab PDA
[b"orderbook", market.key()]
// Request Queue PDA
[b"request_queue", market.key()]
// Event Queue PDA
[b"event_queue", market.key()]
// Vault PDA (holds user collateral)
[b"vault", market.key()]
// Insurance Fund PDA
[b"insurance", market.key()]- Rust 1.70 or higher
- Solana CLI 1.17+
- Anchor 0.29+
- Node.js 18+ (for tests and frontend)
# Clone the repository
git clone https://github.com/yourusername/perdex.git
cd perdex
# Install Anchor
cargo install --git https://github.com/coral-xyz/anchor avm --locked
avm install latest
avm use latest
# Build the program
anchor build
# Run tests
anchor test# Start local validator
solana-test-validator
# Deploy program (in another terminal)
anchor deploy
# Initialize market
anchor run initialize-market
# Start cranker bot
npm run crankerimport * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { PerDEX } from "../target/types/per_dex";
// Connect to devnet
const connection = new anchor.web3.Connection("https://api.devnet.solana.com");
const wallet = anchor.Wallet.local();
const provider = new anchor.AnchorProvider(connection, wallet, {});
const program = anchor.workspace.PerDEX as Program<PerDEX>;
// Place a limit order
const [positionPda] = await anchor.web3.PublicKey.findProgramAddress(
[Buffer.from("position"), wallet.publicKey.toBuffer(), market.toBuffer()],
program.programId
);
await program.methods
.placeOrder({
side: { bid: {} },
orderType: { limit: { price: new anchor.BN(50000), postOnly: false } },
size: new anchor.BN(100),
})
.accounts({
user: wallet.publicKey,
position: positionPda,
market: marketPda,
requestQueue: requestQueuePda,
// ... other accounts
})
.rpc();
// Check position
const position = await program.account.userPosition.fetch(positionPda);
console.log("Position:", position.size.toString(), "@", position.entryPrice.toString());Run comprehensive on-chain tests:
# Run all Anchor tests
anchor test
# Run specific test file
anchor test --test matching_tests
# Run tests on devnet
anchor test --provider.cluster devnet
# Run with detailed logs
RUST_LOG=debug anchor test- Unit tests for slab operations (off-chain)
- Integration tests for complete order flow (on-chain)
- Liquidation scenario tests
- Margin calculation tests
- Concurrent order tests
Expected performance characteristics on Solana:
- Order Placement: ~400ms (network + confirmation)
- Matching: 1-10 orders per crank (compute limit dependent)
- Settlement: Atomic within transaction
- Throughput: 2000-3000 TPS (Solana network limit)
- Finality: ~13 seconds (confirmed), ~30 seconds (finalized)
Markets are configured via on-chain accounts:
#[account]
pub struct Market {
pub authority: Pubkey,
pub oracle: Pubkey, // Pyth/Switchboard price feed
pub base_symbol: String, // e.g., "BTC"
pub quote_symbol: String, // e.g., "USDC"
pub maker_fee_bps: u16, // 2 bps
pub taker_fee_bps: u16, // 5 bps
pub initial_margin_ratio: u16, // 1000 = 10% (10x leverage)
pub maintenance_margin_ratio: u16, // 500 = 5%
pub liquidation_penalty_bps: u16, // 50 bps
pub max_leverage: u8, // e.g., 20x
pub funding_period: i64, // 8 hours
pub vault: Pubkey, // SPL token vault
pub insurance_fund: Pubkey,
pub orderbook: Pubkey,
pub request_queue: Pubkey,
pub event_queue: Pubkey,
}The protocol requires permissionless keepers:
- Monitors request queue
- Calls crank instruction
- Earns crank fees
- Anyone can run
- Monitors positions via RPC
- Calls liquidate instruction when margin insufficient
- Earns liquidation rewards
- Competitive market for liquidations
- Calls update_funding instruction every 8 hours
- Permissionless trigger
- Can be incentivized or run by protocol
This code is for educational purposes and requires professional audits before mainnet deployment.
- Access Control: Anchor's account constraints prevent unauthorized access
- Oracle Manipulation: Price bands and TWAP to prevent flash crashes
- Reentrancy: Solana's single-threaded execution prevents reentrancy
- Integer Overflow: Checked arithmetic throughout
- Signer Verification: All user actions require wallet signature
- Core orderbook and matching engine
- Margin system and liquidations
- Oracle integration (Pyth Network)
- Frontend trading interface
- Keeper bot infrastructure
- Multi-collateral support
- Funding rate mechanism
- Orderbook depth API
- Historical data indexer
- Security audit
- Mainnet deployment
Contributions welcome! Areas for improvement:
- Optimize compute usage in matching algorithm
- Improve slab memory efficiency
- Add more order types (trailing stop, iceberg)
- Build subgraph/indexer for historical data
- Develop UI components
- Write keeper bot examples
Please open an issue before starting major work.
This project is licensed under the MIT License - see the LICENSE file for details.
- Serum DEX: Pioneer of on-chain CLOB on Solana
- Mango Markets: Advanced perpetuals margin system
- Drift Protocol: Innovative hybrid orderbook approach
- Anchor Framework: Making Solana development accessible
- Anchor Documentation
- Solana Cookbook
- Serum Developer Resources
- Pyth Network - Oracle integration
- Perpetual Futures Mechanics
- Twitter: @PerDEX
- Discord: Join our community
- Documentation: docs.perdex.io