Decentralized Exchange (DEX)

Building a simple decentralized exchange for token trading.

Advanced⏱️ 60 min📚 Prerequisites: 1

Decentralized Exchange (DEX)

A Decentralized Exchange allows users to trade tokens without a central authority. Let's build a simple order book DEX.

DEX Components

  1. Order Book: Buy and sell orders
  2. Matching Engine: Matches orders
  3. Liquidity Pool: Alternative AMM model
  4. Trade Execution: Execute matched trades

Order Structure

RUST
enum OrderType {
    Buy,
    Sell,
}

struct Order {
    id: String,
    trader: String,
    order_type: OrderType,
    token_pair: (String, String),  // (base, quote)
    price: u64,
    amount: u64,
    filled: u64,
}

Order Book

RUST
struct OrderBook {
    buy_orders: Vec<Order>,   // Sorted by price (highest first)
    sell_orders: Vec<Order>,  // Sorted by price (lowest first)
}

impl OrderBook {
    fn add_order(&mut self, order: Order) {
        match order.order_type {
            OrderType::Buy => self.buy_orders.push(order),
            OrderType::Sell => self.sell_orders.push(order),
        }
        self.match_orders();
    }
    
    fn match_orders(&mut self) {
        // Match highest buy with lowest sell
        // Execute trades when prices overlap
    }
}

Automated Market Maker (AMM)

Alternative to order books:

RUST
struct LiquidityPool {
    token_a: u64,
    token_b: u64,
    total_supply: u64,
}

impl LiquidityPool {
    fn swap(&mut self, token_in: String, amount_in: u64) -> u64 {
        // Constant product formula: x * y = k
        // Calculate amount_out based on pool reserves
    }
}

Trade Execution

RUST
fn execute_trade(buy_order: &mut Order, sell_order: &mut Order) -> Trade {
    let trade_amount = buy_order.amount.min(sell_order.amount);
    let trade_price = sell_order.price;  // Use sell price
    
    // Update orders
    buy_order.filled += trade_amount;
    sell_order.filled += trade_amount;
    
    Trade {
        buy_order_id: buy_order.id.clone(),
        sell_order_id: sell_order.id.clone(),
        amount: trade_amount,
        price: trade_price,
    }
}

DEX Features

  • No KYC: Permissionless trading
  • Non-custodial: Users control funds
  • Transparent: All trades on-chain
  • Liquidity: Provided by users

Implementation Considerations

  • Slippage: Price impact of large trades
  • Front-running: MEV (Maximal Extractable Value)
  • Gas optimization: Minimize on-chain operations
  • Liquidity incentives: Reward liquidity providers

Code Examples

Order Book

Basic order book implementation

RUST
enum OrderType {
    Buy,
    Sell,
}
struct Order {
    id: String,
    trader: String,
    order_type: OrderType,
    price: u64,
    amount: u64,
}
struct OrderBook {
    buy_orders: Vec<Order>,
    sell_orders: Vec<Order>,
}
impl OrderBook {
    fn new() -> Self {
        OrderBook {
            buy_orders: Vec::new(),
            sell_orders: Vec::new(),
        }
    }
    fn add_order(&mut self, order: Order) {
        match order.order_type {
            OrderType::Buy => {
                self.buy_orders.push(order);
                self.buy_orders.sort_by(|a, b| b.price.cmp(&a.price));
            },
            OrderType::Sell => {
                self.sell_orders.push(order);
                self.sell_orders.sort_by(|a, b| a.price.cmp(&b.price));
            },
        }
    }
    fn get_best_buy(&self) -> Option<&Order> {
        self.buy_orders.first()
    }
    fn get_best_sell(&self) -> Option<&Order> {
        self.sell_orders.first()
    }
}
fn main() {
    let mut book = OrderBook::new();
    book.add_order(Order {
        id: String::from("buy1"),
        trader: String::from("0xAlice"),
        order_type: OrderType::Buy,
        price: 100,
        amount: 10,
    });
    book.add_order(Order {
        id: String::from("sell1"),
        trader: String::from("0xBob"),
        order_type: OrderType::Sell,
        price: 95,
        amount: 5,
    });
    if let Some(best_buy) = book.get_best_buy() {
        println!("Best buy: {} at price {}", best_buy.amount, best_buy.price);
    }
    if let Some(best_sell) = book.get_best_sell() {
        println!("Best sell: {} at price {}", best_sell.amount, best_sell.price);
    }
}

Explanation:

An order book maintains buy and sell orders sorted by price. The best buy (highest price) and best sell (lowest price) can be matched when prices overlap.

AMM Liquidity Pool

Automated Market Maker pool

RUST
struct LiquidityPool {
    token_a_reserve: u64,
    token_b_reserve: u64,
}
impl LiquidityPool {
    fn new(amount_a: u64, amount_b: u64) -> Self {
        LiquidityPool {
            token_a_reserve: amount_a,
            token_b_reserve: amount_b,
        }
    }
    fn swap_a_for_b(&mut self, amount_a_in: u64) -> u64 {
        let k = self.token_a_reserve * self.token_b_reserve;
        self.token_a_reserve += amount_a_in;
        let new_b_reserve = k / self.token_a_reserve;
        let amount_b_out = self.token_b_reserve - new_b_reserve;
        self.token_b_reserve = new_b_reserve;
        amount_b_out
    }
    fn get_price(&self) -> f64 {
        if self.token_a_reserve > 0 {
            self.token_b_reserve as f64 / self.token_a_reserve as f64
        } else {
            0.0
        }
    }
}
fn main() {
    let mut pool = LiquidityPool::new(1000, 2000);
    println!("Initial price: {:.2}", pool.get_price());
    let b_received = pool.swap_a_for_b(100);
    println!("Swapped 100 A for {} B", b_received);
    println!("New price: {:.2}", pool.get_price());
}

Explanation:

AMM pools use constant product formula (x * y = k) to determine swap rates. Prices change based on pool reserves, providing automatic price discovery.

Exercises

Order Book

Create an order book that can add buy and sell orders!

Medium

Starter Code:

RUST
enum OrderType {
    Buy,
    Sell,
}
struct Order {
    price: u64,
    amount: u64,
}
struct OrderBook {
    buy_orders: Vec<Order>,
    sell_orders: Vec<Order>,
}
fn main() {
    let mut book = OrderBook::new();
    book.add_buy_order(Order { price: 100, amount: 10 });
    book.add_sell_order(Order { price: 95, amount: 5 });
    println!("Buy orders: {}, Sell orders: {}",
            book.buy_orders.len(), book.sell_orders.len());
}