Трейдеры привыкли к лимитным ордерам и стаканам на CEX. Но на DeFi-биржах с AMM это недоступно — только market order с проскальзыванием. Мы строим order book DEX, который даёт ликвидность CEX без отказа от децентрализации. Наш опыт — 10+ лет в блокчейне и более 50 проектов, включая интеграции с AMM и L2. Проблемы, которые мы решаем: газовые издержки on-chain хранения (каждый ордер — транзакция, каждый матч — транзакция; при частоте торговли это экономически нецелесообразно — решение: off-chain matching engine + on-chain settlement), front-running и MEV (в публичном мемпуле ордера видны всем; боты могут опередить вашу транзакцию — используем EIP-712 подписи с нестандартными nonce, интеграцию с Flashbots и батчинг транзакций), ликвидность на старте (пустой стакан отпугивает трейдеров — решения: интеграция с AMM-пулами как fallback, RFQ-сервис для institutional ордеров, программа market maker с пониженными комиссиями).
Какую модель order book выбрать?
Fully on-chain order book: order book хранится и матчится прямо в смарт-контракте. Каждый ордер — транзакция. Стоимость газа высока: выставить, отменить, заполнить — всё платит трейдер. Latency ~12 секунд (блок Ethereum). Front-running неизбежен. Подходит только для аукционов и batch settlement.
Off-chain order book + on-chain settlement: доминирующая модель. Matching — off-chain (быстро, бесплатно). Только финальный трейд фиксируется on-chain. Примеры: dYdX v3 (Starkware), Serum (Solana). Off-chain matching лучше полностью on-chain в 10-100 раз по стоимости газа и в 10 раз по скорости.
Hybrid: off-chain orders + on-chain matching: ордера подписываются off-chain (EIP-712), хранятся в off-chain order book, но matching выполняется on-chain при settlement. Пример: 0x Protocol, Hashflow. Maker не платит газ за выставление — только за исполнение.
| Критерий | On-chain | Off-chain + on-chain settlement | Hybrid |
|---|---|---|---|
| Gas cost | Высокий | Низкий | Средний |
| Latency | ~12 сек | <1 сек | <1 сек |
| Complexity | Низкая | Средняя | Высокая |
| Применимость | Аукционы | Профессиональная торговля | Market making |
Смарт-контракты для 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 // for 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); } } Спецификация EIP-712 определяет структуру подписи. Ключевые security-аспекты: filledAmounts для частичного заполнения, usedNonces против replay, обязательный expiry. Для стандартного approve требуется отдельная транзакция — Permit2 от Uniswap Labs решает это одной подписью.
Как работает off-chain matching engine?
Это высокопроизводительный сервис, похожий на CEX matching, но с особенностями:
- Ордера — подписанные сообщения, не on-chain.
- Частичное заполнение отслеживается off-chain и on-chain (mapping filledAmounts).
- Отмена ордера: 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 Сколько экономит батчинг?
Батч из 10 заполнений в одной транзакции экономит ~70% газа по сравнению с 10 отдельными. Функция fillOrderBatch делает это возможным.
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]); } } Что дают L2 и appchain?
Развернуть: dYdX v4 на Cosmos appchain даёт нулевые fees для трейдеров и <1ms latency. Arbitrum / zkSync L2 снижают стоимость газа в 10-100 раз — on-chain ордера становятся экономичными при объёмах >$100. Starkware с validity proofs масштабирует до 10,000+ trades/sec.
Как обеспечить ликвидность на старте?
Интеграция с AMM: если нет market maker — router направляет в AMM-пул (например, Uniswap V3). Market maker программа: пониженные fees, кредитная линия, приоритет matching. RFQ: institutional трейдеры запрашивают котировку напрямую у зарегистрированных MM.
Сравнение с 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 | Зависит от архитектуры | Один блок |
| Сложность | Высокая | Средняя |
Процесс разработки
- Аналитика: выбор блокчейна, L2, модели matching (on-chain/off-chain/hybrid).
- Проектирование: архитектура смарт-контрактов, off-chain сервисов, API.
- Реализация: разработка settlement контрактов, matching engine, интеграция кошельков.
- Тестирование: unit-тесты, интеграционные тесты, фаззинг (Echidna), симуляция на testnet.
- Аудит: автоматический (Slither, Mythril) и ручной код-ревью.
- Деплой: последовательный rollout с мониторингом.
Что входит в работу
Документация архитектуры и API, доступ к исходному коду контрактов и matching engine, инструкции по развёртыванию и мониторингу, обучение команды администрированию, поддержка в течение месяца после деплоя.
Сроки: MVP за 2–3 месяца, полноценная система с L2 и RFQ — от 6 месяцев. Стоимость рассчитывается индивидуально. Свяжитесь для консультации и получите оценку за 2 дня. Закажите разработку, чтобы ускорить выход на рынок.







