סוחרים רגילים לפקודות מגבילות ולספרי הזמנות בבורסות מרכזיות (CEX). אך בבורסות DeFi עם AMM, זה אינו זמין—רק פקודות שוק עם החלקה (slippage). אנו בונים בורסת DEX עם ספר הזמנות המספקת נזילות דומה ל-CEX מבלי לוותר על ביזור. הניסיון שלנו: למעלה מ-10 שנים בבלוקצ'יין ולמעלה מ-50 פרויקטים, כולל אינטגרציות עם AMM ו-L2.
בעיות שאנו פותרים
- עלויות גז לאחסון על-השרשרת: כל פקודה היא עסקה, כל התאמה היא עסקה; בתדירות מסחר, זה לא כלכלי—הפתרון: מנוע התאמה מחוץ לשרשרת + סילוק על-השרשרת.
- Front-running ו-MEV: ב-mempool הציבורי, פקודות גלויות לכולם; בוטים יכולים לבצע front-running לעסקה שלך—אנו משתמשים בחתימות EIP-712 עם nonce לא סטנדרטיים, אינטגרציה עם Flashbots, ואיגוד עסקאות (batching).
- נזילות בהשקה: ספר הזמנות ריק מפחיד סוחרים—פתרונות: אינטגרציה עם מאגרי AMM כגיבוי, שירות RFQ לפקודות מוסדיות, תוכנית market maker עם עמלות מופחתות.
באיזה מודל ספר הזמנות לבחור?
ספר הזמנות מלא על-השרשרת: ספר ההזמנות מאוחסן ומותאם ישירות בחוזה חכם. כל פקודה היא עסקה. עלות גז גבוהה: הצבה, ביטול, מילוי—הכל משולם על ידי הסוחר. זמן השהיה ~12 שניות (בלוק של Ethereum). Front-running בלתי נמנע. מתאים רק למכירות פומביות ולסילוק בקבוצות (batch settlement).
ספר הזמנות מחוץ לשרשרת + סילוק על-השרשרת: המודל הדומיננטי. התאמה—מחוץ לשרשרת (מהיר, חינם). רק העסקה הסופית מסולקת על-השרשרת. דוגמאות: dYdX v3 (Starkware), Serum (Solana). התאמה מחוץ לשרשרת עדיפה על פני מלא על-השרשרת פי 10-100 בעלות גז ופי 10 במהירות.
היברידי: פקודות מחוץ לשרשרת + התאמה על-השרשרת: פקודות חתומות מחוץ לשרשרת (EIP-712), מאוחסנות בספר הזמנות מחוץ לשרשרת, אך ההתאמה מבוצעת על-השרשרת בסילוק. דוגמה: 0x Protocol, Hashflow. Maker אינו משלם גז עבור הצבה—רק עבור ביצוע.
| קריטריון | על-השרשרת | מחוץ לשרשרת + סילוק על-השרשרת | היברידי |
|---|---|---|---|
| עלות גז | גבוהה | נמוכה | בינונית |
| זמן השהיה | ~12 שניות | <1 שנייה | <1 שנייה |
| מורכבות | נמוכה | בינונית | גבוהה |
| התאמה לשימוש | מכירות פומביות | מסחר מקצועי | יצירת שוק (market making) |
חוזים חכמים לסילוק
חתימות פקודות 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 מגדיר את מבנה החתימה. היבטי אבטחה מרכזיים: // 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); } } למילוי חלקי, filledAmounts נגד שימוש חוזר (replay), ו-usedNonces חובה. עבור approve סטנדרטי, נדרשת עסקה נפרדת—Permit2 של Uniswap Labs פותר זאת עם חתימה אחת.
כיצד פועל מנוע ההתאמה מחוץ לשרשרת?
זהו שירות בעל ביצועים גבוהים הדומה למנוע התאמה של CEX, אך עם מאפיינים ייחודיים:
- פקודות הן הודעות חתומות, לא על-השרשרת.
- מילוי חלקי מנוטר מחוץ לשרשרת ועל-השרשרת (מיפוי filledAmounts).
- ביטול פקודה: nonce על-השרשרת או ביטול מחוץ לשרשרת עם אישור 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 עסקאות נפרדות. הפונקציה expiry מאפשרת זאת.
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 מציעה אפס עמלות לסוחרים וזמן השהיה של <1 אלפית שנייה. Arbitrum / zkSync L2 מפחיתות עלות גז פי 10-100—פקודות על-השרשרת הופכות לכלכליות עבור נפחים >$100. Starkware עם הוכחות תקפות (validity proofs) מתמודדת עם למעלה מ-10,000 עסקאות בשנייה.
כיצד להבטיח נזילות בהשקה?
- אינטגרציה עם AMM: אם אין market maker, הנתב מפנה למאגר AMM (לדוגמה, Uniswap V3).
- תוכנית market maker: עמלות מופחתות, מסגרת אשראי, התאמה בעדיפות.
- RFQ: סוחרים מוסדיים מבקשים הצעות מחיר ישירות מ-MM רשומים.
השוואה עם AMM
| קריטריון | בורסת DEX עם ספר הזמנות | בורסת DEX עם AMM |
|---|---|---|
| יעילות הון | גבוהה (ללא נזילות בטלה) | נמוכה (V2) / גבוהה (V3) |
| חוויית משתמש לסוחרים | מוכרת, פקודות מגבילות | פשוטה יותר, שוק בלבד |
| יצירת שוק | דורש מקצוענים | נגיש לכל ספקי הנזילות (LPs) |
| סיכון front-running | גבוה (ללא הגנה) | בינוני (sandwich) |
| זמן השהיה | תלוי בארכיטקטורה | בלוק אחד |
| מורכבות | גבוהה | בינונית |
תהליך הפיתוח
- אנליטיקה: בחירת בלוקצ'יין, L2, מודל התאמה (על-השרשרת/מחוץ לשרשרת/היברידי).
- עיצוב: ארכיטקטורת חוזים חכמים, שירותים מחוץ לשרשרת, API.
- יישום: פיתוח חוזי סילוק, מנוע התאמה, אינטגרציה עם ארנקים.
- בדיקות: בדיקות יחידה, בדיקות אינטגרציה, fuzzing (Echidna), סימולציה ברשת testnet.
- ביקורת: אוטומטית (Slither, Mythril) ובדיקת קוד ידנית.
- פריסה: השקה בשלבים עם ניטור.
מה כלול בעבודה
- תיעוד ארכיטקטורה ו-API
- גישה לקוד המקור של החוזים ומנוע ההתאמה
- הוראות פריסה וניטור
- הכשרת צוות לניהול
- תמיכה לחודש לאחר הפריסה
לוחות זמנים: MVP תוך 2–3 חודשים, מערכת מלאה עם L2 ו-RFQ מ-6 חודשים. העלות מחושבת באופן אישי. צרו קשר לייעוץ וקבלו הערכה תוך יומיים. הזמינו פיתוח כדי להאיץ את זמן היציאה לשוק.







