Skip to content

Turbin3/accel-FluxDEX

Repository files navigation

FluxDEX

A Solana central-limit order book (CLOB) with a DODO-style quadratic PMM fallback — built on Pinocchio (no Anchor) and delegated to MagicBlock ephemeral rollups for ~10 ms execution.

FluxDEX is an exchange-oriented Solana program that combines a price-time-priority order book with a proactive market maker (PMM) fallback. The CLOB matches orders when they cross; the PMM provides oracle-referenced liquidity via a quadratic pricing curve when no resting counterparty exists.

Custody and durable state live on Solana L1. The order book can be delegated to a MagicBlock ephemeral rollup for low-latency, gasless session trading, then committed and undelegated back to L1 — with vault custody never leaving the main chain.

⚠️ NOT PRODUCTION READY. This code has not had a professional security audit. Do not use with real funds.


Why FluxDEX

Most on-chain venues are either a pure AMM (high slippage, impermanent loss) or a pure CLOB (no fallback liquidity when the book is thin). FluxDEX runs both:

  • CLOB as primary — price-time priority matching against resting orders.
  • PMM as fallback — an oracle-anchored quadratic curve fills when the book can't.
  • MagicBlock delegation — the orderbook executes inside an ephemeral session for ~10 ms blocks and gasless, session-key-signed trades.
  • Zero-copy, no Anchorbytemuck::Pod account structs over Pinocchio; tiny CU footprint (e.g. place_order ≈ 14k CU, match_orders ≈ 7k CU).
  • Python-validated math — the PMM curve is specified and tested in Python first, exported as JSON vectors, then ported to Rust.

Architecture

                 +----------------------------------+
                 |        Solana L1 (durable)       |
                 |----------------------------------|
                 | Market config + PMM/oracle params|
                 | Vault custody (base + quote PDAs)|
                 | Orderbook account (CLOB state)   |
                 | Fee accounting + authority/pause |
                 +----------------+-----------------+
                                  |
              delegate / commit / undelegate (MagicBlock DLP)
                                  |
                 +----------------v-----------------+
                 |   MagicBlock Ephemeral Rollup    |
                 |----------------------------------|
                 | ~10 ms block time                |
                 | gasless session-key transactions |
                 | CLOB matching (price-time)       |
                 +----------------+-----------------+
                                  |
                          no CLOB match?
                                  v
                 +----------------------------------+
                 |   PMM Engine (quadratic DODO)    |
                 |----------------------------------|
                 | P = i·(1 − k + k·(B₀/B)²)        |
                 | Pyth oracle price (raw-parsed)   |
                 +----------------------------------+

System Design

The full layered system design — from the trader's wallet down to atomic settlement:

FluxDEX system architecture

Layer Responsibility Key elements
L1 — User Wallet connection + transaction signing Trader connects wallet, signs txs
L2 — Frontend Consumer-grade trading UI /trade, /markets, /portfolio routes; OrderBook, PlaceOrder, Portfolio, MarketStats, LatencyTimer — React · Vite · TailwindCSS · Wallet Adapter · Solana Web3.js · MagicBlock SDK
L3 — RPC / Data Realtime on-chain data RPC endpoint, WebSocket subscriptions, account-change notifications
L4 — Smart contract (Pinocchio) Zero-overhead Solana program with manual account validation initialize_market, place_order, cancel_order, delegate_orderbook, match_orders, settle_trade, undelegate_orderbook (+ admin ixs); owner + discriminator checks, PDA canonical bump stored, CPI pattern enforced
L6 — MagicBlock ephemeral rollup ~10 ms blocks, gasless session txs Delegated orderbook PDA locked on L1 while the ER is active; session executor with gasless session keys → CLOB matching engine (price-time priority, crit-bit tree, O(log n)): cross? YES → atomic fill, NO → PMM fallback
L8 — PMM pricing engine Oracle-referenced quadratic fallback Price = Oracle × (1 + k × skew) — oracle price in, inventory skew, effective price out
Pyth oracle External price feed SOL/USDC feed + confidence interval
L10 — Settlement Atomic delivery-vs-payment via SPL Token CPI SPL Token program CPI transfer (buyer receives), PDA-owned token vaults (unlock escrow), atomic buyer + seller settlement (seller receives), CCTP V2 cross-chain USDC

Tech Stack

Layer Technology
On-chain program Rust 2024, Pinocchio 0.11 (no Anchor)
Serialization bytemuck (zero-copy account state) + wincode (instruction args)
Token CPIs pinocchio-token, pinocchio-associated-token-account, transfer_checked
Oracle Pyth V2 price accounts, parsed from raw bytes (no pyth-sdk dependency)
Rollup / sessions MagicBlock Delegation Program + gpl-session
Tests LiteSVM integration suite
Reference math Python 3.10+ (quadratic PMM + JSON test vectors)
Frontend React 18, Vite, TypeScript, TailwindCSS, Solana Wallet Adapter, MagicBlock SDK
CI GitHub Actions (fmt, clippy -D warnings, SBF build + cargo test)

Repository Layout

accel-FluxDEX/
├── src/                      # On-chain program (Pinocchio)
│   ├── lib.rs                #   entrypoint + instruction dispatch
│   ├── instruction.rs        #   discriminators, arg structs, account contexts
│   ├── processor.rs          #   all 14 instruction handlers
│   ├── state.rs              #   Market / Order / Orderbook (zero-copy)
│   ├── error.rs              #   FluxDexError (37 variants)
│   ├── oracle.rs             #   Pyth price-account parsing & validation
│   ├── pmm.rs                #   quadratic PMM math (Rust port)
│   └── magicblock.rs         #   delegation / undelegate-callback CPIs
├── prototype/                # Python PMM reference + test-vector generator
│   ├── pmm_math.py           #   marginal price, integral, solver, regression
│   ├── cli.py                #   interactive CLI (tables, ASCII curve, calc)
│   ├── test_vectors.py       #   emits JSON vectors → prototype/vectors/
│   └── vectors/              #   pricing / integral / swap / slippage / regression
├── tests/
│   ├── flux_dex_tests.rs     #   LiteSVM integration suite (95 tests)
│   └── fixtures/             #   delegation_program.so, session_program.so
├── app/                      # React + Vite + TS frontend
├── docs/                     # PRD, TDD (source of truth), epics, screenshots
├── deploy/deploy-devnet.sh   # devnet deploy helper
├── justfile                  # build / test / lint / pmm task runner
└── Cargo.toml

Instruction Set

The program dispatches on a single leading discriminator byte (plus an 8-byte discriminator reserved for the MagicBlock undelegate callback).

# Discriminator Instruction Purpose
0 INIT_MARKET initialize_market Create market PDA + base/quote vaults
1 PLACE_ORDER place_order Place a bid/ask (optional session-key account)
2 CANCEL_ORDER cancel_order Cancel a resting order, refund escrow
3 DELEGATE_ORDERBOOK delegate_orderbook Hand the orderbook to the ephemeral rollup
4 UNDELEGATE_ORDERBOOK undelegate_orderbook Request return of the orderbook to L1
5 UPDATE_ORDERBOOK update_orderbook Reconcile session-diff state on L1
6 MATCH_ORDERS match_orders Crank: match crossing orders (optional oracle)
7 SETTLE_TRADE settle_trade Atomically move tokens + accrue fees
8 SET_MARKET_PARAMS set_market_params Tune fee, PMM k/B₀, oracle limits
9 PROPOSE_AUTHORITY propose_authority Step 1 of two-step authority rotation
10 ACCEPT_AUTHORITY accept_authority Step 2 (timelocked) — new authority accepts
11 WITHDRAW_FEES withdraw_fees Authority withdraws accumulated quote fees
12 SET_PAUSE set_market_pause Halt/resume trading (recovery paths stay open)
13 CANCEL_AUTHORITY_PROPOSAL cancel_authority_proposal Abort a pending rotation
8-byte callback handle_undelegate_callback DLP CPI returning the orderbook to L1

On-Chain State

All account structs are #[repr(C)], bytemuck::Pod, with every multi-byte field stored as a little-endian [u8; N] array (alignment 1, no padding). Typed values are read/written through getters. See src/state.rs and docs/TDD.md §4.

Account Discriminator Size Notes
Market 1 265 B authority, mints, vaults, fee, PMM params, cached oracle price, session expiry, two-step authority + timelock, accumulated fees, pause flag
Order 2 128 B trader, side, price, quantity, status
Orderbook 3 43 B header fixed header + dynamic tail of order entries

Security Model

The program was hardened in dedicated audit passes (commits #68/#69). Highlights:

  • #![deny(clippy::unwrap_used)] crate-wide — no panics in handler paths.
  • Checked arithmetic everywhere; overflow checks on in release profile.
  • Per-instruction account validation: exact account counts, signer checks, writable checks, real program-ID checks, and duplicate mutable account guards (e.g. vaults must differ and can't double as settlement destinations).
  • SPL transfer_checked (validates mint + decimals) for every token movement.
  • Oracle price validation: configurable max confidence ratio (default 5%) and max staleness (default 60 s); price is cached in Market.
  • Two-step, timelocked authority rotation; pausable trading with fund-recovery paths (withdraw_fees) left open even when paused.

Despite this, the code is unaudited. Treat all of the above as defense-in-depth, not a guarantee.


PMM Math

Quadratic DODO pricing curve (full derivation in docs/TDD.md and prototype/README.md):

Marginal price:
  P = i · (1 − k + k · (B₀/B)²)     when B > B₀  (base excess → price drops)
  P = i / (1 − k + k · (B/B₀)²)     when B < B₀  (base deficit → price rises)

Integral (average fill price):
  ΔQ = i · ΔB · (1 − k + k · B₀² / (B₁ · B₂))

Quadratic solver (quote → base):
  a·ΔB² + b·ΔB + c = 0

Regression target (IL recovery):
  ΔB = (√(B₀² − (B₀² − B²)(1 − k)) − B₀) / k

The Python reference (prototype/pmm_math.py) emits JSON vectors consumed by the Rust port in src/pmm.rs.


Prerequisites

  • Rust (stable) — via rustup. Toolchain pinned in rust-toolchain.toml.
  • Solana CLI — provides cargo build-sbf. Install from anza.xyz.
  • Node.js 18+ — for the frontend in app/.
  • Python 3.10+ — for the PMM prototype and vector generation.
  • just (optional)cargo install just.

Getting Started

1. Build the program

cargo build-sbf            # → target/deploy/flux_dex.so
# or: just build

2. Run the tests

The LiteSVM suite loads the compiled target/deploy/flux_dex.so, so you must build the SBF artifact first (CI does exactly this):

cargo build-sbf            # rebuild whenever src/ changes
cargo test                 # 95 integration tests + unit tests

⚠️ cargo test does not rebuild the .so. If you edit src/ and forget to re-run cargo build-sbf, tests run against a stale binary and fail with InvalidAccountCount (error 28). Always rebuild first.

3. Run the frontend

cd app
cp .env.example .env       # configure RPC + program ID
npm install
npm run dev                # http://localhost:5173
npm test                   # 22 vitest tests

4. Deploy to devnet

cargo build-sbf
./deploy/deploy-devnet.sh                      # uses ~/.config/solana/id.json
./deploy/deploy-devnet.sh ~/.config/solana/devnet.json   # custom deployer

Devnet program ID: 3onsNSU7Q8v5yZ14wTY9DnNHr76WSxwjfnD1jrDyZAPc (deploying with your own program keypair yields your own ID.)


Frontend (app/)

React + Vite + TypeScript + TailwindCSS trading interface.

  • Pages — Landing, Markets, Trade, Portfolio (react-router-dom).
  • Wallet@solana/wallet-adapter-react connection + UI.
  • MagicBlock — session-key management and delegation via @magicblock-labs/ephemeral-rollups-sdk and gum-react-sdk (src/lib/magicblock.ts, src/hooks/useSession.ts).
  • Deposits — CCTP V2 cross-chain USDC deposit flow (src/lib/cctp.ts, useDeposit.ts, DepositModal.tsx).
  • Data hooksuseMarketData, useOrderBook, useWallet, useDeposit.

Environment variables (app/.env.example):

Variable Description Default
VITE_SOLANA_CLUSTER devnet | mainnet-beta | localnet devnet
VITE_RPC_ENDPOINT Override RPC endpoint (recommended in prod) cluster public URL
VITE_MAGIC_ROUTER_ENDPOINT MagicBlock Magic Router endpoint devnet router
VITE_FLUXDEX_PROGRAM_ID Deployed program ID devnet ID above

Commands (just)

Command Description
just build Build the SBF program (cargo build-sbf)
just test Run the test suite
just lint cargo fmt --all + clippy (-D warnings -D unwrap_used)
just check fmt-check + clippy (CI parity)
just pmm PMM CLI — tables + ASCII curve + interactive calculator
just pmm-table / just pmm-curve / just pmm-interactive Individual PMM views
just pmm-vectors Regenerate JSON test vectors
just deploy-devnet Deploy to devnet
just all check + test + regenerate vectors

Run just --list for the full set.


Testing

# On-chain program (build .so first!)
cargo build-sbf && cargo test

# Frontend
cd app && npm test

# Python PMM reference
just pmm                 # interactive CLI
just pmm-vectors         # regenerate JSON vectors

CI (.github/workflows/ci.yml) runs three jobs on every push/PR to main: fmt (cargo fmt --check), clippy (-D warnings -D clippy::unwrap_used), and test (installs the Solana CLI, runs cargo build-sbf, then cargo test).

Screenshots

Test 1 Test 2 Test 3 Test 4


Key Files to Read First

  1. docs/TDD.md — technical design and source of truth (PMM math, state layout, instruction interface, security model).
  2. src/instruction.rs — the full instruction/account ABI.
  3. prototype/pmm_math.py — the PMM reference implementation.
  4. docs/prd.md — product requirements and open questions.

Roadmap

  1. Epic 1 — Foundation — scaffolding, state.rs, error.rs, CI/CD ✅
  2. Epic 2 — Smart contract — all 14 instruction handlers + security hardening ✅
  3. Epic 3 — Frontend — React/Vite trading interface ✅
  4. Epic 4 — Integration — MagicBlock delegation, Pyth oracle, CCTP V2, deployment 🚧

See docs/epics/ for the full ticket breakdown.


License

Apache 2.0 — see LICENSE.

About

FluxDEX is a hybrid CLOB + PMM (Proactive Market Maker) decentralized exchange built on Solana

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors