Трейдеры привыкли к лимитным ордерам и стаканам на 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 дня. Закажите разработку, чтобы ускорить выход на рынок.







