Central Limit Order Book
Boros implements a gas-optimized central limit order book (CLOB) specifically designed for the EVM. The order book architecture minimizes gas costs through lazy settlement and efficient data structures while maintaining the functionality expected from professional trading platforms.
Order Book Structureβ
The order book consists of two independent sides:
- Long Side (Bids): Orders to buy/go long on interest rates
- Short Side (Asks): Orders to sell/go short on interest rates
Each side contains 65,536 discrete rate levels (ticks) ranging from -32768 to 32767.
The tick system uses an exponential function to map discrete tick indices to interest rates. This design provides:
- Compactness: Entire rate range expressed with just 16 bits
- Expressiveness: Finer granularity near zero, coarser at extremes
- Symmetry: Equal precision for positive and negative rates
The tick spacing is configurable per market via the tickStep parameter. A larger tickStep creates wider rate intervals between ticks, suitable for more volatile markets.
Tick vs Rateβ
Ticks are for the order book only. The order book uses integer tick values to represent discrete rate levels. The AMM, on the other hand, operates with continuous rates (not ticks). This distinction is important:
- Order placement requires an integer
tickvalue β you cannot place orders at arbitrary rates - AMM implied rate is a continuous value and does not correspond to any specific tick
- Mid APR is typically
(bestBid + bestAsk) / 2or the AMM implied rate, which is a continuous value that generally cannot be expressed as an integer tick - When converting a rate to a tick for order placement, you must round to the nearest valid tick β this introduces a small rounding difference
Tick to Rate Conversionβ
The conversion between tick indices and interest rates follows an exponential formula:
The TickMath library provides conversion between tick indices and interest rates:
// Convert tick to interest rate
int128 rate = TickMath.getRateAtTick(tick, tickStep);
// Formula: rate = 1.00005^(tick * tickStep) - 1 for tick >= 0
// rate = -(1.00005^(-tick * tickStep) - 1) for tick < 0
Examplesβ
// tickStep = 2
tick = 0 -> rate = 0% (neutral)
tick = 100 -> rate = 1.00005^200 - 1 β 1.005%
tick = -100 -> rate = -(1.00005^200 - 1) β -1.005%
Matching Priorityβ
Boros order book follows the standard rate-time priority matching:
- Orders offering better rates are matched first
- For long orders: Higher rates (willing to pay more) have priority
- For short orders: Lower rates (willing to receive less) have priority
- Within the same rate level (tick), orders are matched in the order they were placed (FIFO)
- The
orderIndexwithin each tick determines the exact queue position
- The
Order Idβ
Each order in Boros has a unique order Id within its market. The combination of (Market ID, Order ID) is the globally unique identifier. Order IDs may be reused across different markets β do not use the Order ID alone as a unique key.
The order Id is a 64-bit packed value containing order metadata:
OrderId structure (64 bits):
βββββββββββ¬βββββββββββββββ¬βββββββββββ¬ββββββββββββββ¬βββββββββββββββ
β Init(1) β Reserved(6) β Side(1) β Tick(16) β Index(40) β
βββββββββββ΄βββββββββββββββ΄βββββββββββ΄ββββββββββββββ΄βββββββββββββββ
Bit 63: Initialization marker (always 1 for valid orders)
Bits 57-62: Reserved
Bit 56: Side (0 = LONG, 1 = SHORT)
Bits 40-55: Encoded tick index
Bits 0-39: Order index within tick
This encoding has a nice ordering property: orders with lower OrderId values have higher priority in the order book.
Parsing OrderIdβ
// Parsing an OrderId
(Side side, int16 tickIndex, uint40 orderIndex) = OrderIdLib.unpack(orderId);
// Quick access methods
Side side = orderId.side();
int16 tick = orderId.tickIndex();
uint40 index = orderId.orderIndex();
Placing ordersβ
Time In Forceβ
Time In Force (TIF) parameters control how orders behave during matching and placement. Boros supports five TIF types: GTC, IOC, FOK, ALO, and SOFT_ALO. See Custom Types β TimeInForce for descriptions of each type.
Self-trade Preventionβ
Boros prevents self-trading by checking if an incoming order would match against the same account's existing orders. If self-matching is detected, the transaction will revert to protect traders from unintentionally trading with themselves.
Restrictionsβ
Order Size:
- No minimum order size requirement
- No lot size restrictions - any decimal amount supported
- Orders must have non-zero size
Order Limits:
- Maximum open orders per account across all sides (configurable per market via
maxOpenOrders, typically 100) - Exceeding this limit will cause the transaction to revert
Rate Bounds (Taker Orders) β "Large Rate Deviation":
- When an order matches and executes (taker fill), the resulting trade rate is checked against the mark rate
- If the rate deviates too much from the mark rate, the transaction reverts with
Large Rate Deviation- Buy/Long orders: Rejected if executed rate is too far above the mark rate
- Sell/Short orders: Rejected if executed rate is too far below the mark rate
- The acceptable deviation is governed by
maxRateDeviationFactorBase1e4in the market config - When placing closing orders (reducing position), a separate, more lenient bound
closingOrderBoundBase1e4applies
Limit Order Rate Bounds (Maker Orders) β "Rate too far off":
- Limit orders placed on the book have additional rate constraints
- If a maker order's rate is too far from the mark rate, it is rejected with
Rate too far off - The bounds are controlled by four parameters in the market config:
Upper Bound = Mark Rate Γ (1 + loUpperConst + loUpperSlope Γ Time to Maturity)
Lower Bound = Mark Rate Γ (1 - loLowerConst - loLowerSlope Γ Time to Maturity)
These parameters ensure limit orders remain within a reasonable range of the current mark rate, scaling with time to maturity.
Large Rate Deviationβ applies to taker fills (IOC, FOK, or the matched portion of GTC). Your trade's execution rate is too far from the mark rate.Rate too far offβ applies to maker orders (the resting portion placed on the book). Your order's rate is too far from the mark rate to be placed.
Order Lifecycleβ
Beyond normal cancellation, orders can be removed by the protocol's risk management system β including force-cancellation of risky accounts' orders and purging of out-of-bound orders (which receive the PURGED status). See Risk Management Actions for details.
For order status values, see Custom Types β OrderStatus.
TWAP Oracle (Mark Rate)β
Boros maintains a Time-Weighted Average Price (TWAP) oracle to calculate the mark rate β the reference rate used for margining, liquidations, and order rate bounds. The mark rate is essentially the TWAP of historical trades.
Each time an order is matched against the order book, the rate of the last matched tick is incorporated into the TWAP calculation based on time elapsed.
The oracle uses a fixed-window observation approach:
markRate = (lastTradedRate Γ timeElapsed + prevOracleRate Γ (window - timeElapsed)) / window
The mark rate is distinct from the mid rate (midpoint of best bid and best ask) and the AMM implied rate. In normal conditions, these values should be close, but they can diverge in thin markets or when the AMM operates outside its active range.