Разработка DEX на базе order book

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Разработка DEX на базе order book
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    920
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1147
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    885

Разработка DEX на базе order book

Order book DEX — это децентрализованная биржа, которая использует модель книги ордеров вместо AMM-пула. Трейдеры выставляют limit ордера, matching engine сводит их. Принципиальный вопрос: где живёт order book и где происходит matching? Ответ определяет всю архитектуру.

Три модели order book DEX

Fully on-chain order book

Order book хранится и матчится прямо в смарт-контракте. Каждый ордер — транзакция. Каждый матч — транзакция.

Проблемы:

  • Стоимость газа: выставить ордер = транзакция. Отменить = транзакция. Заполнить = транзакция. Трейдеры платят газ за каждое действие, включая ордера которые никогда не исполнились
  • Latency: блок Ethereum = ~12 секунд. Нельзя "быстро" скальпировать
  • Front-running: все ордера видны в mempool

Применимо только для: аукционов, batch settlement систем, низкочастотной торговли

Off-chain order book + on-chain settlement

Это доминирующая модель. Order book и matching — off-chain (быстро, бесплатно). Settlement финального трейда — on-chain через смарт-контракт.

Примеры: dYdX v3 (Starkware), Injective Protocol, Serum (Solana)

Hybrid: off-chain orders + on-chain matching

Ордера подписываются off-chain (EIP-712), хранятся в off-chain orderbook, но matching выполняется on-chain при settlement. Пример: 0x Protocol, Hashflow.

Преимущество: maker не платит газ за выставление ордера — только за исполнение. Это критично для market makers.

Смарт-контракты для settlement

EIP-712 подписи ордеров

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract OrderBookSettlement {
    bytes32 public constant ORDER_TYPEHASH = keccak256(
        "Order(address maker,address taker,address makerToken,address takerToken,"
        "uint256 makerAmount,uint256 takerAmount,uint256 nonce,uint256 expiry)"
    );

    struct Order {
        address maker;
        address taker;       // address(0) = any taker
        address makerToken;
        address takerToken;
        uint256 makerAmount;
        uint256 takerAmount;
        uint256 nonce;
        uint256 expiry;
    }

    mapping(address => mapping(uint256 => bool)) public usedNonces;
    mapping(bytes32 => uint256) public filledAmounts; // partial fills

    function fillOrder(
        Order calldata order,
        bytes calldata signature,
        uint256 takerFillAmount  // для partial fills
    ) external {
        require(block.timestamp < order.expiry, "ORDER_EXPIRED");
        require(
            order.taker == address(0) || order.taker == msg.sender,
            "INVALID_TAKER"
        );

        bytes32 orderHash = getOrderHash(order);
        require(
            filledAmounts[orderHash] + takerFillAmount <= order.takerAmount,
            "OVERFILL"
        );

        // Verify EIP-712 signature
        address recovered = recoverSigner(orderHash, signature);
        require(recovered == order.maker, "INVALID_SIGNATURE");

        // Calculate maker amount proportional to partial fill
        uint256 makerFillAmount = (order.makerAmount * takerFillAmount) / order.takerAmount;

        filledAmounts[orderHash] += takerFillAmount;

        // Atomic swap
        IERC20(order.takerToken).transferFrom(msg.sender, order.maker, takerFillAmount);
        IERC20(order.makerToken).transferFrom(order.maker, msg.sender, makerFillAmount);

        emit OrderFilled(orderHash, order.maker, msg.sender, makerFillAmount, takerFillAmount);
    }
}

Ключевые security аспекты:

  • filledAmounts отслеживает частичные заполнения — ордер можно заполнять постепенно
  • usedNonces предотвращает replay атаки
  • expiry обязателен — без него maker не может контролировать когда ордер исполнится
  • transferFrom требует предварительного approve от обеих сторон

Permit2 (Uniswap)

Проблема стандартного approve: пользователь должен отправить отдельную транзакцию approve перед каждым взаимодействием с контрактом. Permit2 (UniswapLabs) решает это:

// Permit2: подписанное разрешение без on-chain approve транзакции
struct PermitTransferFrom {
    TokenPermissions permitted;
    uint256 nonce;
    uint256 deadline;
}

// Maker подписывает разрешение вместе с ордером — одна подпись = всё

Это улучшает UX для maker-ов: они подписывают ордер + permit одной EIP-712 подписью, без предварительных approve транзакций.

Off-chain matching engine

Архитектура

Matching engine для order book DEX — это высокопроизводительный сервис, похожий на CEX matching, но с особенностями:

  1. Ордера не хранятся on-chain — они существуют как подписанные сообщения
  2. Частичное заполнение должно отслеживаться off-chain И on-chain (through filledAmounts mapping)
  3. Отмена ордера = либо on-chain nonce инвалидация, либо off-chain "cancel" с подтверждением от maker-а
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional
import asyncio

@dataclass
class SignedOrder:
    maker: str
    taker_token: str
    maker_token: str
    taker_amount: Decimal
    maker_amount: Decimal
    nonce: int
    expiry: int
    signature: str

    @property
    def price(self) -> Decimal:
        """Цена в единицах maker_token за taker_token"""
        return self.maker_amount / self.taker_amount

    @property
    def is_expired(self) -> bool:
        import time
        return time.time() > self.expiry


class OffChainOrderBook:
    def __init__(self, pair: str):
        self.pair = pair
        self.bids: list[SignedOrder] = []  # buy orders, sorted by price DESC
        self.asks: list[SignedOrder] = []  # sell orders, sorted by price ASC
        self._settlement_queue = asyncio.Queue()

    async def add_order(self, order: SignedOrder, side: str):
        if side == 'bid':
            self.bids.append(order)
            self.bids.sort(key=lambda x: x.price, reverse=True)
        else:
            self.asks.append(order)
            self.asks.sort(key=lambda x: x.price)

        await self.try_match()

    async def try_match(self):
        while self.bids and self.asks:
            best_bid = self.bids[0]
            best_ask = self.asks[0]

            if best_bid.is_expired:
                self.bids.pop(0)
                continue
            if best_ask.is_expired:
                self.asks.pop(0)
                continue

            if best_bid.price >= best_ask.price:
                # Match found
                fill_amount = min(best_bid.taker_amount, best_ask.taker_amount)
                await self._settlement_queue.put({
                    'bid': best_bid,
                    'ask': best_ask,
                    'fill_amount': fill_amount
                })

                # Update or remove filled orders
                best_bid.taker_amount -= fill_amount
                best_ask.taker_amount -= fill_amount

                if best_bid.taker_amount == 0:
                    self.bids.pop(0)
                if best_ask.taker_amount == 0:
                    self.asks.pop(0)
            else:
                break

Settlement батчинг

On-chain settlement дорогой. Стратегия: батчить матчи и отправлять несколько заполнений в одной транзакции.

function fillOrderBatch(
    Order[] calldata orders,
    bytes[] calldata signatures,
    uint256[] calldata fillAmounts
) external {
    require(orders.length == signatures.length, "LENGTH_MISMATCH");

    for (uint256 i = 0; i < orders.length; i++) {
        fillOrder(orders[i], signatures[i], fillAmounts[i]);
    }
}

Батч из 10 заполнений экономит ~70% газа по сравнению с 10 отдельными транзакциями (overhead фиксирован, execution дешевле).

L2 и appchain подходы

dYdX v4 архитектура: cosmos appchain

dYdX v4 перешёл с Starkware L2 на собственный Cosmos SDK appchain. Order book и matching — полностью off-chain на validators. On-chain только финальные settlements.

Преимущества: нулевые fees для трейдеров (газ платит протокол из trading fees), <1ms matching latency, полная децентрализация matching (распределён между validators).

Arbitrum / zkSync L2 подход

Deploying on L2 снижает стоимость газа в 10-100 раз. Для order book DEX это означает: on-chain order placement становится экономически целесообразным для ордеров >$100.

Пример: Lighter.xyz построен на Arbitrum, использует fully on-chain matching, достигая ~1,000 orders/sec при cost ~$0.01/order.

Starkware / zkProofs

dYdX v3 использовал StarkEx: matching off-chain, validity proofs submitted on-chain. ZK-proof подтверждает корректность всех операций без необходимости их replay на-chain. Масштабируемость: 10,000+ trades/sec с on-chain security.

Ликвидность: проблема холодного старта

Order book DEX без market makers = пустой стакан. Решения:

Integrations с AMM: если нет market maker на какой-то паре — router автоматически исполняет через AMM-пул. Гибридная модель: order book + AMM fallback.

Market maker программа: специальные условия для designated market makers — сниженные fees, кредитная линия, приоритет в matching.

RFQ (Request for Quote): вместо публичного order book — запрос котировки напрямую к зарегистрированным market makers. Используется Hashflow, Airswap. Лучший execution для крупных ордеров.

Трейдер → broadcast RFQ → Market Makers
                               ↓
Market Makers → ответные котировки (подписанные off-chain)
                               ↓
Трейдер → выбирает лучшую → on-chain settlement

RFQ идеально подходит для institutional-размера ордеров, где AMM slippage неприемлем.

Сравнение с AMM

Критерий Order Book DEX AMM DEX
Capital efficiency Высокая (нет idle ликвидности) Низкая (V2) / Высокая (V3)
UX для трейдеров Familiar, limit orders Проще, только market
Market making Нужны профессионалы Доступно всем LP
Front-running risk Высокий (без protect) Средний (sandwich)
Latency Зависит от архитектуры Один блок
Сложность Высокая Средняя

Для большинства DeFi-проектов AMM проще в запуске. Order book DEX стоит строить если: целевая аудитория — профессиональные трейдеры, нужны limit orders, или работаете на L2/appchain с низкими fees.