This project is a high-performance cryptocurrency exchange built entirely in Rust. It features a modular architecture with separate components for the API, matching engine, WebSocket server, and database services.
The exchange is a monorepo containing the following crates:
api: The public-facing RESTful API built withactix-web. It handles user requests, such as placing orders, checking balances, and getting market data.engine: The core matching engine of the exchange. It processes orders, matches trades, and maintains the order book for each market. It's designed for high performance and low latency.wss: A WebSocket server built withtokio-tungstentinethat provides real-time data streams to clients. Users can subscribe to channels to receive live updates on trades, order book changes, and their own user data.db_filler: Fills the market data such as place new orders, updating orders, cancelling orders and adding trades by getting messages from engine. Usestokioas the runtime.store: Handles all database interactions usingsqlxwith a PostgreSQL database. It's responsible for persisting trades, orders, and user data.common: A shared library containing common data structures, types, and utilities used across all other crates.
-
Set up the environment:
- Clone the repository.
- Create a
.envfile in the root of the project and add the necessary environment variables for database connections, Redis URLs, and other configurations. You can use the.env.examplefile as a template. Or you can runcp .env.example .envfor the default values.
-
Starting Services (via Docker):
- Run
docker run -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgresto start a postgres database. - Run
docker run -d -p 6379:6379 redisto start a redis server.
- Run
-
Run DB migrations:
- First of all, you need to have a
sqlx-cliinstalled to run the database migrations. - Navigate to the
storedirectorycd store. - Now run migrations using the command
sqlx migrate run
- First of all, you need to have a
-
Run the exchange components:
- Each component can be run separately. Open a new terminal for each service.
- Engine:
cargo run --bin engine - Database Filler:
cargo run --bin db_filler - WebSocket Server:
cargo run --bin wss - API Server:
cargo run --bin api
Screencast.from.2025-07-10.09-39-06.webm
- Initially client subscribes to the WSS server at channels like trade@SOL_USDC , depth@SOL_USDC. Then WSS subscribes to those channels on
WSS_PUB_SUB. - Then client sends a POST req to create an order to
api apicreates an order_id for the order. Then subscribes to thatorder_idonAPI_PUB_SUBand pushes the order toorders QUEUE.manageror the main core of the engine constantly get's order fromorders QUEUEand sends the order to the correct orderbook.Orderbookvalidates and locks user funds. Then process against opposing orders and may sit on the orderbook if unfilled incase of limit order. Finally Settles the balance of makers and taker.- Then
Orderbooksends:- Order and Trade details to
DB_Filler QUEUE, - Order Status and Filled Quantity of Order to
API_PUB_SUB. - Trade and Depth details to
WSS_PUB_SUB.
- Order and Trade details to
apireceives the order details fromAPI_PUB_SUBand sends response to the client.DB_Fillerthen gets the trade and order details and updates to the DBWSS servergets updates about trade and depth details to the Subscribed Clients
The following is a summary of the available API endpoints based on the code structure.
GET /health: Checks the health of the API server.POST /order: Create a new order.DELETE /order: Cancel an existing order.GET /orders/open: Get all open orders for a user.POST /order/cancel_all: Cancel all open orders for a user.GET /depth: Get the order book depth for a market.GET /balance: Get the user's account balance.GET /trade/history: Get the trade history for a market.
The WebSocket server provides real-time data streams. Connect to ws://127.0.0.1:8081 and subscribe to the following channels:
- Order Book: Get real-time updates on the order book for a specific market.
- Trades: Receive live trade updates for a market.
- UserId's - random1, random2, random32 are set with initial balances for ease.
- OrderBook Recovery
- Testing
Contributions are welcome! Please feel free to open an issue or submit a pull request 🙏.