@zoralabs/limit-orders 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$js.log +85 -0
- package/AUDIT_NOTES.md +33 -0
- package/AUDIT_RFP.md +408 -0
- package/CHANGELOG.md +25 -0
- package/GAS_COMPARISON_RESULTS.md +194 -0
- package/LICENSE +21 -0
- package/README.md +650 -0
- package/SPEC.md +291 -0
- package/abis/BalanceDeltaLibrary.json +15 -0
- package/abis/BeforeSwapDeltaLibrary.json +15 -0
- package/abis/CurrencyLibrary.json +25 -0
- package/abis/CustomRevert.json +28 -0
- package/abis/IAllowanceTransfer.json +486 -0
- package/abis/IAuthority.json +31 -0
- package/abis/ICoin.json +1074 -0
- package/abis/IDeployedCoinVersionLookup.json +21 -0
- package/abis/IDopplerErrors.json +44 -0
- package/abis/IEIP712.json +15 -0
- package/abis/IERC1363.json +373 -0
- package/abis/IERC165.json +21 -0
- package/abis/IERC20.json +185 -0
- package/abis/IERC20Minimal.json +172 -0
- package/abis/IERC6909Claims.json +288 -0
- package/abis/IERC7572.json +21 -0
- package/abis/IExtsload.json +64 -0
- package/abis/IExttload.json +40 -0
- package/abis/IHasCoinType.json +15 -0
- package/abis/IHasPoolKey.json +42 -0
- package/abis/IHasRewardsRecipients.json +54 -0
- package/abis/IHasSwapPath.json +60 -0
- package/abis/IHasTotalSupplyForPositions.json +15 -0
- package/abis/IHooks.json +789 -0
- package/abis/IMsgSender.json +15 -0
- package/abis/IPoolManager.json +1286 -0
- package/abis/IProtocolFees.json +174 -0
- package/abis/ISupportsLimitOrderFill.json +15 -0
- package/abis/ISwapPathRouter.json +92 -0
- package/abis/ISwapRouter.json +219 -0
- package/abis/IUniswapV3SwapCallback.json +25 -0
- package/abis/IUpgradeableDestinationV4Hook.json +84 -0
- package/abis/IUpgradeableDestinationV4HookWithUpdateableFee.json +95 -0
- package/abis/IUpgradeableV4Hook.json +112 -0
- package/abis/IZoraHookRegistry.json +188 -0
- package/abis/IZoraLimitOrderBook.json +623 -0
- package/abis/IZoraLimitOrderBookCoinsInterface.json +67 -0
- package/abis/IZoraV4CoinHook.json +610 -0
- package/abis/Permit2Payments.json +7 -0
- package/abis/Position.json +7 -0
- package/abis/SafeCast.json +7 -0
- package/abis/SafeCast160.json +7 -0
- package/abis/SafeERC20.json +34 -0
- package/abis/SimpleAccessManaged.json +57 -0
- package/abis/SimpleAccessManager.json +351 -0
- package/abis/SqrtPriceMath.json +22 -0
- package/abis/StateLibrary.json +80 -0
- package/abis/SwapLimitOrders.json +22 -0
- package/abis/SwapWithLimitOrders.json +457 -0
- package/abis/TickBitmap.json +18 -0
- package/abis/TickMath.json +24 -0
- package/abis/V3ToV4SwapLib.json +28 -0
- package/abis/ZoraLimitOrderBook.json +771 -0
- package/cache/solidity-files-cache.json +1 -0
- package/dist/index.cjs +760 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +731 -0
- package/dist/index.js.map +1 -0
- package/dist/wagmiGenerated.d.ts +1012 -0
- package/dist/wagmiGenerated.d.ts.map +1 -0
- package/foundry.toml +29 -0
- package/gas_comparison.py +49 -0
- package/out/BalanceDelta.sol/BalanceDeltaLibrary.json +1 -0
- package/out/BeforeSwapDelta.sol/BeforeSwapDeltaLibrary.json +1 -0
- package/out/BitMath.sol/BitMath.json +1 -0
- package/out/BytesLib.sol/BytesLib.json +1 -0
- package/out/CoinCommon.sol/CoinCommon.json +1 -0
- package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -0
- package/out/CoinConstants.sol/CoinConstants.json +1 -0
- package/out/Context.sol/Context.json +1 -0
- package/out/Currency.sol/CurrencyLibrary.json +1 -0
- package/out/CurrencyReserves.sol/CurrencyReserves.json +1 -0
- package/out/CustomRevert.sol/CustomRevert.json +1 -0
- package/out/DopplerMath.sol/DopplerMath.json +1 -0
- package/out/FixedPoint128.sol/FixedPoint128.json +1 -0
- package/out/FixedPoint96.sol/FixedPoint96.json +1 -0
- package/out/FullMath.sol/FullMath.json +1 -0
- package/out/IAllowanceTransfer.sol/IAllowanceTransfer.json +1 -0
- package/out/IAuthority.sol/IAuthority.json +1 -0
- package/out/ICoin.sol/ICoin.json +1 -0
- package/out/ICoin.sol/IHasCoinType.json +1 -0
- package/out/ICoin.sol/IHasPoolKey.json +1 -0
- package/out/ICoin.sol/IHasSwapPath.json +1 -0
- package/out/ICoin.sol/IHasTotalSupplyForPositions.json +1 -0
- package/out/IDeployedCoinVersionLookup.sol/IDeployedCoinVersionLookup.json +1 -0
- package/out/IDopplerErrors.sol/IDopplerErrors.json +1 -0
- package/out/IEIP712.sol/IEIP712.json +1 -0
- package/out/IERC1363.sol/IERC1363.json +1 -0
- package/out/IERC165.sol/IERC165.json +1 -0
- package/out/IERC20.sol/IERC20.json +1 -0
- package/out/IERC20Minimal.sol/IERC20Minimal.json +1 -0
- package/out/IERC6909Claims.sol/IERC6909Claims.json +1 -0
- package/out/IERC7572.sol/IERC7572.json +1 -0
- package/out/IExtsload.sol/IExtsload.json +1 -0
- package/out/IExttload.sol/IExttload.json +1 -0
- package/out/IHasRewardsRecipients.sol/IHasRewardsRecipients.json +1 -0
- package/out/IHooks.sol/IHooks.json +1 -0
- package/out/IMsgSender.sol/IMsgSender.json +1 -0
- package/out/IPoolManager.sol/IPoolManager.json +1 -0
- package/out/IProtocolFees.sol/IProtocolFees.json +1 -0
- package/out/ISupportsLimitOrderFill.sol/ISupportsLimitOrderFill.json +1 -0
- package/out/ISwapPathRouter.sol/ISwapPathRouter.json +1 -0
- package/out/ISwapRouter.sol/ISwapRouter.json +1 -0
- package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -0
- package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4Hook.json +1 -0
- package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4HookWithUpdateableFee.json +1 -0
- package/out/IUpgradeableV4Hook.sol/IUpgradeableV4Hook.json +1 -0
- package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -0
- package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -0
- package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -0
- package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -0
- package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -0
- package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -0
- package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -0
- package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -0
- package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -0
- package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -0
- package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -0
- package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -0
- package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -0
- package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -0
- package/out/LiquidityMath.sol/LiquidityMath.json +1 -0
- package/out/Lock.sol/Lock.json +1 -0
- package/out/NonzeroDeltaCount.sol/NonzeroDeltaCount.json +1 -0
- package/out/Path.sol/Path.json +1 -0
- package/out/PathKey.sol/PathKeyLibrary.json +1 -0
- package/out/Permit2Payments.sol/Permit2Payments.json +1 -0
- package/out/PoolId.sol/PoolIdLibrary.json +1 -0
- package/out/Position.sol/Position.json +1 -0
- package/out/SafeCast.sol/SafeCast.json +1 -0
- package/out/SafeCast160.sol/SafeCast160.json +1 -0
- package/out/SafeERC20.sol/SafeERC20.json +1 -0
- package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +1 -0
- package/out/SimpleAccessManager.sol/SimpleAccessManager.json +1 -0
- package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -0
- package/out/StateLibrary.sol/StateLibrary.json +1 -0
- package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -0
- package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -0
- package/out/TickBitmap.sol/TickBitmap.json +1 -0
- package/out/TickMath.sol/TickMath.json +1 -0
- package/out/TransientSlot.sol/TransientSlot.json +1 -0
- package/out/TransientStateLibrary.sol/TransientStateLibrary.json +1 -0
- package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -0
- package/out/UnsafeMath.sol/UnsafeMath.json +1 -0
- package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -0
- package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -0
- package/out/build-info/69718f10d1dc37f0.json +1 -0
- package/out/uniswap/BitMath.sol/BitMath.json +1 -0
- package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -0
- package/out/uniswap/FullMath.sol/FullMath.json +1 -0
- package/out/uniswap/SafeCast.sol/SafeCast.json +1 -0
- package/out/uniswap/TickMath.sol/TickMath.json +1 -0
- package/package/index.ts +1 -0
- package/package/wagmiGenerated.ts +738 -0
- package/package.json +57 -0
- package/remappings.txt +11 -0
- package/src/IZoraLimitOrderBook.sol +195 -0
- package/src/ZoraLimitOrderBook.sol +220 -0
- package/src/access/SimpleAccessManaged.sol +76 -0
- package/src/access/SimpleAccessManager.sol +268 -0
- package/src/libs/LimitOrderBitmap.sol +84 -0
- package/src/libs/LimitOrderCommon.sol +91 -0
- package/src/libs/LimitOrderCreate.sol +277 -0
- package/src/libs/LimitOrderFill.sol +362 -0
- package/src/libs/LimitOrderLiquidity.sol +222 -0
- package/src/libs/LimitOrderQueues.sol +101 -0
- package/src/libs/LimitOrderStorage.sol +34 -0
- package/src/libs/LimitOrderTypes.sol +41 -0
- package/src/libs/LimitOrderWithdraw.sol +100 -0
- package/src/libs/Permit2Payments.sol +41 -0
- package/src/libs/SwapLimitOrders.sol +209 -0
- package/src/router/SwapWithLimitOrders.sol +454 -0
- package/test/LimitOrderAccessControl.t.sol +461 -0
- package/test/LimitOrderBitmap.t.sol +194 -0
- package/test/LimitOrderCreate.t.sol +348 -0
- package/test/LimitOrderFill.t.sol +1005 -0
- package/test/LimitOrderLibraries.t.sol +354 -0
- package/test/LimitOrderLiquidityPayouts.t.sol +333 -0
- package/test/LimitOrderV4Pools.t.sol +157 -0
- package/test/LimitOrderWithdraw.t.sol +653 -0
- package/test/SimpleAccessManager.t.sol +420 -0
- package/test/SwapWithLimitOrders.t.sol +107 -0
- package/test/SwapWithLimitOrdersRouter.t.sol +1073 -0
- package/test/gas/LimitOrderFillGas.t.sol +1008 -0
- package/test/gas/LimitOrderSwapGas.t.sol +403 -0
- package/test/gas/logs/gas_benchmarks_fill_20251201.log +30 -0
- package/test/gas/logs/gas_benchmarks_swap_20251201.log +27 -0
- package/test/unit/LimitOrderBitmapUnit.t.sol +276 -0
- package/test/unit/LimitOrderCreateUnit.t.sol +358 -0
- package/test/unit/SwapLimitOrdersUnit.t.sol +672 -0
- package/test/unit/SwapLimitOrdersValidation.t.sol +423 -0
- package/test/unit/SwapWithLimitOrdersUnit.t.sol +321 -0
- package/test/utils/BaseTest.sol +793 -0
- package/test/utils/TestableZoraLimitOrderBook.sol +54 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +11 -0
- package/wagmi.config.ts +18 -0
package/SPEC.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Zora Limit Orders — Protocol Spec (Auditor & Integrator Facing)
|
|
2
|
+
|
|
3
|
+
This document is the **behavioral specification** for the Limit Orders system in `packages/limit-orders/`.
|
|
4
|
+
|
|
5
|
+
Related docs:
|
|
6
|
+
|
|
7
|
+
- [`README.md`](./README.md) — architecture & diagrams (canonical “where to start”)
|
|
8
|
+
- [`AUDIT_NOTES.md`](./AUDIT_NOTES.md) — threat model & audit checklist
|
|
9
|
+
- [`AUDIT_RFP.md`](./AUDIT_RFP.md) — audit scope & deliverables
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Glossary
|
|
14
|
+
|
|
15
|
+
- **PoolKey / poolKeyHash**: Uniswap V4 pool identity / hash.
|
|
16
|
+
- **tick**: Discrete price index for concentrated liquidity.
|
|
17
|
+
- **tickSpacing**: The pool’s tick granularity; all order ticks are aligned to it.
|
|
18
|
+
- **order**: A single-sided liquidity position representing a limit order.
|
|
19
|
+
- **queue**: FIFO linked-list of orders at a given `(poolKeyHash, coin, tick)`.
|
|
20
|
+
- **bitmap**: Tracks which ticks have active queues for a given `(poolKeyHash, coin)`.
|
|
21
|
+
- **epoch**: Monotonic counter per pool used to prevent same-transaction fill of newly-created orders.
|
|
22
|
+
- **maker**: Address that creates an order and receives proceeds/refunds.
|
|
23
|
+
- **filler**: Address/contract that triggers filling (hook, router, or third party).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. System Overview (Normative)
|
|
28
|
+
|
|
29
|
+
### 2.1 Orders as Uniswap V4 positions
|
|
30
|
+
|
|
31
|
+
Each order corresponds to a Uniswap V4 position:
|
|
32
|
+
|
|
33
|
+
- **Range**: one tickSpacing-wide range: \([tickLower, tickUpper]\) with `tickUpper = tickLower + tickSpacing` (direction-dependent).
|
|
34
|
+
- **Salt**: derived from `orderId` (orderId is deterministic).
|
|
35
|
+
- **Funds**: deposited as one side of the range; the other side is received when filled via swaps/burn.
|
|
36
|
+
|
|
37
|
+
### 2.2 Order status model
|
|
38
|
+
|
|
39
|
+
Orders have statuses:
|
|
40
|
+
|
|
41
|
+
- `OPEN`: active in queue + has liquidity position.
|
|
42
|
+
- `FILLED`: liquidity removed/settled; proceeds attributed/paid out.
|
|
43
|
+
- `INACTIVE`: cancelled/withdrawn (not fillable).
|
|
44
|
+
|
|
45
|
+
Allowed transitions (conceptual):
|
|
46
|
+
|
|
47
|
+
- `OPEN -> FILLED`
|
|
48
|
+
- `OPEN -> INACTIVE`
|
|
49
|
+
|
|
50
|
+
No other transitions should be possible.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 3. External API Spec (Normative)
|
|
55
|
+
|
|
56
|
+
This section defines **intended behavior** for the public entrypoints. For exact types/events/errors, reference `src/IZoraLimitOrderBook.sol`.
|
|
57
|
+
|
|
58
|
+
### 3.1 `create(...)`
|
|
59
|
+
|
|
60
|
+
[`ZoraLimitOrderBook.sol:69`](./src/ZoraLimitOrderBook.sol#L69) → [`LimitOrderCreate.sol:44`](./src/libs/LimitOrderCreate.sol#L44)
|
|
61
|
+
|
|
62
|
+
**Purpose**
|
|
63
|
+
|
|
64
|
+
- Adds single-sided V4 liquidity positions for each requested order, and records them into the onchain order book.
|
|
65
|
+
|
|
66
|
+
**Authorization**
|
|
67
|
+
|
|
68
|
+
- `create()` is access-controlled via `SimpleAccessManaged` authority checks.
|
|
69
|
+
|
|
70
|
+
**Effects**
|
|
71
|
+
|
|
72
|
+
- For each order:
|
|
73
|
+
- Transfers funds from maker to the system (direct transfer or Permit2 path depending on router/integration).
|
|
74
|
+
- Mints V4 liquidity for the order range, using `orderId` as salt.
|
|
75
|
+
- Records a `LimitOrder` struct, inserts it into its `(poolKeyHash, coin, tick)` queue, and sets bitmap bit if first at tick.
|
|
76
|
+
- Updates maker balance accounting for `balanceOf()` style queries.
|
|
77
|
+
- Refunds any rounding dust per implementation rules.
|
|
78
|
+
|
|
79
|
+
**Failure modes (examples; non-exhaustive)**
|
|
80
|
+
|
|
81
|
+
- Unauthorized caller.
|
|
82
|
+
- Invalid tick alignment / range.
|
|
83
|
+
- Invalid pool key / unsupported currencies.
|
|
84
|
+
- Insufficient funds / transfer failures.
|
|
85
|
+
- Invalid order configuration.
|
|
86
|
+
|
|
87
|
+
### 3.2 `fill(...)` (range-based)
|
|
88
|
+
|
|
89
|
+
[`ZoraLimitOrderBook.sol:81`](./src/ZoraLimitOrderBook.sol#L81) → [`LimitOrderFill.sol:60`](./src/libs/LimitOrderFill.sol#L60)
|
|
90
|
+
|
|
91
|
+
**Purpose**
|
|
92
|
+
|
|
93
|
+
- Fills as many orders as possible within a tick range (bounded by `maxFillCount`), removing their liquidity and paying proceeds.
|
|
94
|
+
|
|
95
|
+
**Authorization**
|
|
96
|
+
|
|
97
|
+
- When PoolManager is **unlocked**: restricted (only registered hooks, per implementation).
|
|
98
|
+
- When PoolManager is **locked**: callable by anyone.
|
|
99
|
+
|
|
100
|
+
**Epoch isolation**
|
|
101
|
+
|
|
102
|
+
- At the start of a fill execution for a pool, epoch increments.
|
|
103
|
+
- Any order created in the **current** epoch must not be fillable until a later epoch.
|
|
104
|
+
|
|
105
|
+
**Effects**
|
|
106
|
+
|
|
107
|
+
- Iterates ticks with active queues via bitmap, traverses queues FIFO, and processes up to `maxFillCount` fills.
|
|
108
|
+
- For each filled order:
|
|
109
|
+
- Removes order from queue and clears bitmap bit if tick becomes empty.
|
|
110
|
+
- Burns liquidity, performs required swap path (if configured), and pays out maker and referral amounts per configured rules.
|
|
111
|
+
- Marks order status as `FILLED`.
|
|
112
|
+
|
|
113
|
+
### 3.3 `fill(...)` (orderId-based)
|
|
114
|
+
|
|
115
|
+
[`ZoraLimitOrderBook.sol:125`](./src/ZoraLimitOrderBook.sol#L125) → [`LimitOrderFill.sol:60`](./src/libs/LimitOrderFill.sol#L60)
|
|
116
|
+
|
|
117
|
+
**Purpose**
|
|
118
|
+
|
|
119
|
+
- Fills specific order IDs (bounded by `maxFillCount` or batch size per implementation).
|
|
120
|
+
|
|
121
|
+
**Authorization**
|
|
122
|
+
|
|
123
|
+
- Same unlocked/locked restrictions as range-based fill.
|
|
124
|
+
|
|
125
|
+
**Effects**
|
|
126
|
+
|
|
127
|
+
- For each order ID:
|
|
128
|
+
- Validates order status and pool binding.
|
|
129
|
+
- Applies epoch rule (order cannot be filled in its creation epoch).
|
|
130
|
+
- Burns liquidity + pays out, and updates queue/bitmap/bookkeeping.
|
|
131
|
+
|
|
132
|
+
### 3.4 `withdraw(orderIds, coin, minAmountOut, recipient)`
|
|
133
|
+
|
|
134
|
+
[`ZoraLimitOrderBook.sol:141`](./src/ZoraLimitOrderBook.sol#L141) → [`LimitOrderWithdraw.sol:26`](./src/libs/LimitOrderWithdraw.sol#L26)
|
|
135
|
+
|
|
136
|
+
**Purpose**
|
|
137
|
+
|
|
138
|
+
- Cancels specific maker orders by ID and withdraws resulting funds to `recipient` (optionally meeting `minAmountOut`).
|
|
139
|
+
|
|
140
|
+
**Authorization**
|
|
141
|
+
|
|
142
|
+
- Maker-only (must own each order being withdrawn).
|
|
143
|
+
|
|
144
|
+
**Effects**
|
|
145
|
+
|
|
146
|
+
- Processes `orderIds` sequentially until either:
|
|
147
|
+
- `minAmountOut` is reached, or
|
|
148
|
+
- all provided orders are processed.
|
|
149
|
+
- For each cancelled order:
|
|
150
|
+
- Removes order from queue and clears bitmap bit if tick becomes empty.
|
|
151
|
+
- Burns liquidity and refunds (or swaps to payout currency, depending on configuration).
|
|
152
|
+
- Marks order as `INACTIVE`.
|
|
153
|
+
|
|
154
|
+
**Important behavioral clarifications (should remain true)**
|
|
155
|
+
|
|
156
|
+
- Withdrawal is **whole-order only** (no partial cancellation).
|
|
157
|
+
- User funds are always withdrawable regardless of create/fill admin settings (assuming underlying Uniswap V4 invariants hold).
|
|
158
|
+
|
|
159
|
+
### 3.5 Admin functions
|
|
160
|
+
|
|
161
|
+
**`setMaxFillCount(uint256 newMaxFillCount)`**
|
|
162
|
+
|
|
163
|
+
- Updates the stored default max fills per call.
|
|
164
|
+
- Must not allow admin to withdraw user funds or block withdrawals.
|
|
165
|
+
|
|
166
|
+
**Authority management**
|
|
167
|
+
|
|
168
|
+
- Authority contract can be updated as per `SimpleAccessManaged` design.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 4. Storage & Indexing (Normative)
|
|
173
|
+
|
|
174
|
+
### 4.1 Primary indices
|
|
175
|
+
|
|
176
|
+
- **Orders**: `orderId -> LimitOrder`
|
|
177
|
+
- **Queues**: `(poolKeyHash, coin, tick) -> Queue(head, tail, length, balance)`
|
|
178
|
+
- **Bitmap**: `(poolKeyHash, coin) -> tick bitmap words`
|
|
179
|
+
- **Epoch**: `poolKeyHash -> epoch`
|
|
180
|
+
- **Maker balances**: `(maker, coin) -> makerBalance`
|
|
181
|
+
- **Nonces**: `maker -> nonce` (for deterministic order IDs)
|
|
182
|
+
|
|
183
|
+
### 4.2 Deterministic order ID
|
|
184
|
+
|
|
185
|
+
Order IDs are deterministic hashes of the identifying tuple (see implementation in `LimitOrderCreate.sol`).
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 5. Protocol Invariants (Auditor Checklist)
|
|
190
|
+
|
|
191
|
+
This is the “must always hold” list auditors should continuously verify.
|
|
192
|
+
|
|
193
|
+
### 5.1 Queue invariants
|
|
194
|
+
|
|
195
|
+
- **Head/tail consistency**:
|
|
196
|
+
- If `length == 0`: `head == 0` and `tail == 0`.
|
|
197
|
+
- If `length > 0`: `head != 0` and `tail != 0`.
|
|
198
|
+
- **Link integrity**:
|
|
199
|
+
- No cycles in `nextId`/`prevId`.
|
|
200
|
+
- `head.prevId == 0` and `tail.nextId == 0`.
|
|
201
|
+
- For each node: `orders[next].prevId == current` and `orders[prev].nextId == current` (when those neighbors exist).
|
|
202
|
+
- **FIFO**:
|
|
203
|
+
- Enqueue appends at `tail`.
|
|
204
|
+
- Fills traverse from `head` forward.
|
|
205
|
+
- **Balance accounting**:
|
|
206
|
+
- `Queue.balance` equals sum of `orderSize` (or intended accounting field) across `OPEN` orders in that queue.
|
|
207
|
+
|
|
208
|
+
### 5.2 Bitmap invariants
|
|
209
|
+
|
|
210
|
+
- A bitmap bit for a tick is **set iff** the queue at that tick has `length > 0`.
|
|
211
|
+
- Removing the last order at a tick clears the bit.
|
|
212
|
+
- Word-boundary transitions in tick iteration must not skip active ticks or loop infinitely.
|
|
213
|
+
|
|
214
|
+
### 5.3 Epoch invariants
|
|
215
|
+
|
|
216
|
+
- Epoch is per-pool and monotonically increases only at the start of fill executions.
|
|
217
|
+
- An order created in epoch `e` cannot be filled during epoch `e`.
|
|
218
|
+
- Nested create-during-fill must not allow immediate same-epoch fill (intent: deferred to next fill).
|
|
219
|
+
|
|
220
|
+
### 5.4 Order status invariants
|
|
221
|
+
|
|
222
|
+
- `OPEN` orders must be present in exactly one queue, and that queue key must match the order’s `(poolKeyHash, coin, tickLower/tick)` binding.
|
|
223
|
+
- `FILLED` / `INACTIVE` orders must not remain linked in a queue.
|
|
224
|
+
|
|
225
|
+
### 5.5 Maker balance invariants
|
|
226
|
+
|
|
227
|
+
- For a given `(maker, coin)`, `makerBalance` must equal the sum of `orderSize` (or intended accounting field) over all `OPEN` orders owned by maker for that coin.
|
|
228
|
+
- Any decrement must happen exactly once on fill or withdraw/cancel.
|
|
229
|
+
|
|
230
|
+
### 5.6 Uniswap V4 settlement invariants (integration)
|
|
231
|
+
|
|
232
|
+
- All currency deltas created by `modifyLiquidity`, `swap`, `take`, `settle`, and `sync` within an unlock must be settled before completion.
|
|
233
|
+
- The contract must not rely on external token balances changing mid-unlock in unexpected ways.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 6. Observability (Events & Indexing)
|
|
238
|
+
|
|
239
|
+
Auditors/integrators should validate that emitted events are sufficient to:
|
|
240
|
+
|
|
241
|
+
- Track created orders (orderId, maker, pool key binding, tick, size, direction).
|
|
242
|
+
- Track fills (orderId, amounts out, fees, referral).
|
|
243
|
+
- Track withdrawals/cancellations.
|
|
244
|
+
|
|
245
|
+
If events are insufficient for an indexer to reconstruct state, document the intended “indexer model” explicitly (event-sourced vs state-queried).
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 7. Fee & Incentive Model (Normative)
|
|
250
|
+
|
|
251
|
+
### 7.1 How fees accrue
|
|
252
|
+
|
|
253
|
+
Each limit order is a Uniswap V4 liquidity position. While the order is open and swaps occur through the pool, the position accrues LP fees from trades that cross through its tick range.
|
|
254
|
+
|
|
255
|
+
### 7.2 Fee distribution on fill
|
|
256
|
+
|
|
257
|
+
When an order is filled, the `fill()` function accepts a `fillReferral` parameter:
|
|
258
|
+
|
|
259
|
+
- **If `fillReferral == address(0)`**: All proceeds (liquidity + accrued fees) go to the maker.
|
|
260
|
+
- **If `fillReferral != address(0)`**: The maker receives the liquidity proceeds, and the fill referral receives the accrued LP fees.
|
|
261
|
+
|
|
262
|
+
This creates an incentive for third parties to fill orders — they can claim the LP fees that have accumulated on the position.
|
|
263
|
+
|
|
264
|
+
### 7.3 Fee distribution on withdrawal
|
|
265
|
+
|
|
266
|
+
When a maker withdraws (cancels) their order via `withdraw()`:
|
|
267
|
+
|
|
268
|
+
- The maker receives all proceeds (liquidity + any accrued fees).
|
|
269
|
+
- No fill referral is involved since the maker is cancelling their own order.
|
|
270
|
+
|
|
271
|
+
### 7.4 Incentive structure
|
|
272
|
+
|
|
273
|
+
| Actor | Incentive |
|
|
274
|
+
| ------------------ | ----------------------------------------------------------------- |
|
|
275
|
+
| Maker | Receives swap proceeds when order fills; can withdraw at any time |
|
|
276
|
+
| Fill Referral | Receives accrued LP fees from filled positions |
|
|
277
|
+
| Third-party Filler | Can pass their own address as `fillReferral` to collect fees |
|
|
278
|
+
|
|
279
|
+
This design ensures orders will eventually be filled even without hook or router integration — third parties are economically incentivized to monitor and fill orders to capture the accrued fees.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 8. Integration Modes
|
|
284
|
+
|
|
285
|
+
Three fill paths exist (detailed in README):
|
|
286
|
+
|
|
287
|
+
- **Auto-fill via hook** (new hook versions calling `fill` during `afterSwap`).
|
|
288
|
+
- **Router fill fallback** for legacy hooks (router calls `fill` post-swap).
|
|
289
|
+
- **Third-party fill** for pools without hook integration or swaps bypassing the router.
|
|
290
|
+
|
|
291
|
+
Integrators should confirm which path applies for their pool/hook versioning and whether the hook registry restriction applies during unlock.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"name": "ADDRESS_ZERO",
|
|
5
|
+
"inputs": [],
|
|
6
|
+
"outputs": [
|
|
7
|
+
{
|
|
8
|
+
"name": "",
|
|
9
|
+
"type": "address",
|
|
10
|
+
"internalType": "Currency"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"stateMutability": "view"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "error",
|
|
17
|
+
"name": "ERC20TransferFailed",
|
|
18
|
+
"inputs": []
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "error",
|
|
22
|
+
"name": "NativeTransferFailed",
|
|
23
|
+
"inputs": []
|
|
24
|
+
}
|
|
25
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "error",
|
|
4
|
+
"name": "WrappedError",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "target",
|
|
8
|
+
"type": "address",
|
|
9
|
+
"internalType": "address"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "selector",
|
|
13
|
+
"type": "bytes4",
|
|
14
|
+
"internalType": "bytes4"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "reason",
|
|
18
|
+
"type": "bytes",
|
|
19
|
+
"internalType": "bytes"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "details",
|
|
23
|
+
"type": "bytes",
|
|
24
|
+
"internalType": "bytes"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|