# OrderBook.sol

STRIKE 二元结果协议的 central limit order book。单个部署合约管理所有市场。

## 存储

* **市场:** `mapping(uint256 => Market)` — 市场 ID 到市场描述信息。
* **订单:** `mapping(uint256 => Order)` — 订单 ID 到订单 struct。
* **Segment trees:** 每个市场、每个 side（bid/ask/sellYes/sellNo）各有一棵树，用于跟踪每个 tick 的聚合成交量。

### 订单 Struct

```solidity
struct Order {
    // --- Slot 1 (31 bytes) ---
    address owner;       // 20 bytes — order placer
    Side side;           // 1 byte  — Bid, Ask, SellYes, or SellNo
    OrderType orderType; // 1 byte  — GTC or GTB
    uint8 tick;          // 1 byte  — price tick 1-99 (price = tick/100)
    uint64 lots;         // 8 bytes — remaining lots (each lot = LOT_SIZE = 1e16 = $0.01)
    // --- Slot 2 (21 bytes) ---
    uint64 id;           // 8 bytes — unique order ID
    uint32 marketId;     // 4 bytes — market this order belongs to
    uint32 batchId;      // 4 bytes — batch ID when order was placed
    uint40 timestamp;    // 5 bytes — block.timestamp when placed
}
```

该 struct 紧凑打包为 2 个 storage slot，以提升 Gas 效率。

## 关键函数

### `placeOrder(marketId, side, orderType, tick, lots)`

* 校验: tick 在 \[1,99] 内，lots > 0，lots >= minLots，市场处于活跃且未暂停状态。
* **交易停止:** 如果 `block.timestamp + batchInterval >= expiryTime`，则拒绝下单。
* **Side enum:** `Bid` (0), `Ask` (1), `SellYes` (2), `SellNo` (3)。
* 在金库中锁定抵押资产（Bid/Ask），或托管结果代币（SellYes/SellNo）：
* **Bid:** `lots * LOT_SIZE * tick / 100` USDT
* **Ask:** `lots * LOT_SIZE * (100 - tick) / 100` USDT
* **SellYes:** 将 `lots` YES 代币转入订单簿（ERC-1155，用于 non-internal 市场）。
* **SellNo:** 将 `lots` NO 代币转入订单簿（ERC-1155，用于 non-internal 市场）。
* 按 tick 更新线段树聚合量。

> **Internal positions:** 对于使用 `useInternalPositions = true` 的市场（当前 5 分钟市场），SellYes 及 SellNo 使用 internal position balances，而非 ERC-1155 代币转账。

### `placeOrders(marketId, OrderParam[])`

* 批量下单，即在单笔交易中提交多个订单。
* 对所有订单的总抵押资产执行一次金库 deposit，相比逐笔调用 `placeOrder` 更节省 Gas。
* 每个 `OrderParam` 指定 `(side, orderType, tick, lots)`。
* 返回订单 ID 数组。

### `replaceOrders(marketId, cancelOrderIds[], OrderParam[])`

* 原子化取消并下单，即在单笔交易中取消现有订单并提交新订单。
* 净额结算: 仅对抵押资产差额执行 deposit 或退款。
* 适用于重新调整订单位置，无需分别发送取消交易和下单交易。

### OrderParam Struct

```solidity
struct OrderParam {
    Side side;           // Bid, Ask, SellYes, or SellNo
    OrderType orderType; // GoodTilBatch or GoodTilCancel
    uint8 tick;          // price tick 1-99
    uint64 lots;         // number of lots
}
```

### `cancelOrder(orderId)`

* 仅订单所有者可以调用。
* 解锁抵押资产（Bid/Ask），或返还已托管代币（SellYes/SellNo）。
* 更新线段树。
* 市场活跃期间可用。

### `registerMarket(minLots, batchInterval, expiryTime)`

* 仅 OPERATOR\_ROLE 可调用（MarketFactory）。
* 使用给定参数创建新市场。

## Anti-Spam: 每用户订单上限

每个用户在每个市场最多只能拥有 **MAX\_USER\_ORDERS = 20** 个活跃订单。`activeOrderCount[marketId][user]` mapping 会在下单时递增，并在取消或结算时递减。该限制在 `placeOrder`、`placeOrders` 和 `replaceOrders` 中强制执行。

## 休眠订单（价格接近度过滤）

距离上次清算 tick 超过 **PROXIMITY\_THRESHOLD = 20 ticks** 的订单会进入休眠列表，而不是插入线段树。

| 存储 / Function                 | Description                                                                             |
| ----------------------------- | --------------------------------------------------------------------------------------- |
| `restingOrderIds[marketId]`   | 每个市场的休眠订单 ID 数组                                                                         |
| `isResting[orderId]`          | 订单当前是否在休眠列表中                                                                            |
| `isTickFar(marketId, tick)`   | 如果 `tick` 与上次清算 tick 的距离超过 PROXIMITY\_THRESHOLD，则返回 true                                |
| `pullRestingOrders(marketId)` | 将范围内的休眠订单移回线段树（最多拉取 **MAX\_RESTING\_PULL = 200** 个，最多扫描 **MAX\_RESTING\_SCAN = 400** 个） |

休眠订单仍然锁定抵押资产或代币，并且可以正常取消。系统会触发 `OrderResting` 事件，而不是 `OrderPlaced`。

## 访问控制

* **OPERATOR\_ROLE:** 授予 BatchAuction（用于 `reduceOrderLots`、`updateTreeVolume`、`advanceBatch`、`pullRestingOrders`）及 MarketFactory（用于 `registerMarket`、`deactivateMarket`）。

## 事件

```solidity
event MarketRegistered(uint256 indexed marketId, uint256 minLots);
event MarketHalted(uint256 indexed marketId);
event MarketResumed(uint256 indexed marketId);
event MarketDeactivated(uint256 indexed marketId);
event OrderPlaced(uint256 indexed orderId, uint256 indexed marketId, address indexed owner, Side side, uint256 tick, uint256 lots, uint256 batchId);
event OrderResting(uint256 indexed orderId, uint256 indexed marketId, address indexed owner, Side side, uint256 tick, uint256 lots);
event OrderCancelled(uint256 indexed orderId, address indexed owner);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.strike.pm/zh/zhi-neng-he-yue/orderbook.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
