@zoralabs/limit-orders 0.2.0 → 0.2.1

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.
Files changed (84) hide show
  1. package/.turbo/turbo-build$colon$js.log +47 -45
  2. package/CHANGELOG.md +61 -0
  3. package/abis/IWETH.json +118 -0
  4. package/abis/IZoraLimitOrderBook.json +5 -0
  5. package/abis/LimitOrderLiquidity.json +7 -0
  6. package/abis/LimitOrderViews.json +62 -0
  7. package/abis/SwapWithLimitOrders.json +18 -11
  8. package/abis/ZoraLimitOrderBook.json +28 -0
  9. package/cache/solidity-files-cache.json +1 -1
  10. package/dist/index.cjs +29 -8
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.js +29 -8
  13. package/dist/index.js.map +1 -1
  14. package/dist/wagmiGenerated.d.ts +37 -9
  15. package/dist/wagmiGenerated.d.ts.map +1 -1
  16. package/out/BytesLib.sol/BytesLib.json +1 -1
  17. package/out/CoinCommon.sol/CoinCommon.json +1 -1
  18. package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -1
  19. package/out/CoinConstants.sol/CoinConstants.json +1 -1
  20. package/out/DopplerMath.sol/DopplerMath.json +1 -1
  21. package/out/FixedPoint96.sol/FixedPoint96.json +1 -1
  22. package/out/ISwapRouter.sol/ISwapRouter.json +1 -1
  23. package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -1
  24. package/out/IWETH.sol/IWETH.json +1 -0
  25. package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -1
  26. package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -1
  27. package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -1
  28. package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -1
  29. package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -1
  30. package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -1
  31. package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -1
  32. package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -1
  33. package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -1
  34. package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -1
  35. package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -1
  36. package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -1
  37. package/out/LimitOrderViews.sol/LimitOrderViews.json +1 -0
  38. package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -1
  39. package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -1
  40. package/out/Path.sol/Path.json +1 -1
  41. package/out/Permit2Payments.sol/Permit2Payments.json +1 -1
  42. package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +1 -1
  43. package/out/SimpleAccessManager.sol/SimpleAccessManager.json +1 -1
  44. package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -1
  45. package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -1
  46. package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -1
  47. package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -1
  48. package/out/UnsafeMath.sol/UnsafeMath.json +1 -1
  49. package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -1
  50. package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -1
  51. package/out/build-info/{69718f10d1dc37f0.json → 876cc09bc44cc8a7.json} +1 -1
  52. package/out/uniswap/BitMath.sol/BitMath.json +1 -1
  53. package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -1
  54. package/out/uniswap/FullMath.sol/FullMath.json +1 -1
  55. package/out/uniswap/SafeCast.sol/SafeCast.json +1 -1
  56. package/out/uniswap/TickMath.sol/TickMath.json +1 -1
  57. package/package/wagmiGenerated.ts +28 -7
  58. package/package.json +1 -1
  59. package/src/IZoraLimitOrderBook.sol +2 -0
  60. package/src/ZoraLimitOrderBook.sol +22 -8
  61. package/src/libs/LimitOrderBitmap.sol +0 -51
  62. package/src/libs/LimitOrderCommon.sol +48 -30
  63. package/src/libs/LimitOrderCreate.sol +5 -18
  64. package/src/libs/LimitOrderFill.sol +32 -161
  65. package/src/libs/LimitOrderLiquidity.sol +92 -71
  66. package/src/libs/LimitOrderViews.sol +168 -0
  67. package/src/libs/LimitOrderWithdraw.sol +13 -4
  68. package/src/libs/SwapLimitOrders.sol +14 -7
  69. package/src/router/SwapWithLimitOrders.sol +40 -26
  70. package/test/LimitOrderBitmap.t.sol +13 -7
  71. package/test/LimitOrderFill.t.sol +43 -0
  72. package/test/LimitOrderLibraries.t.sol +18 -10
  73. package/test/LimitOrderLiquidityPayouts.t.sol +280 -3
  74. package/test/LimitOrderWithdraw.t.sol +28 -1
  75. package/test/SwapWithLimitOrders.t.sol +3 -3
  76. package/test/SwapWithLimitOrdersRouter.t.sol +108 -11
  77. package/test/unit/LimitOrderBitmapUnit.t.sol +0 -134
  78. package/test/unit/LimitOrderCreateUnit.t.sol +32 -0
  79. package/test/unit/SwapLimitOrdersUnit.t.sol +231 -33
  80. package/test/unit/SwapLimitOrdersValidation.t.sol +20 -34
  81. package/test/unit/SwapWithLimitOrdersUnit.t.sol +21 -88
  82. package/test/utils/BaseTest.sol +29 -8
  83. package/test/utils/MockWETH.sol +39 -0
  84. package/test/utils/TestableZoraLimitOrderBook.sol +5 -7
@@ -14,6 +14,7 @@ contract SwapLimitOrdersValidationTest is Test {
14
14
 
15
15
  PoolKey internal testKey;
16
16
  int24 constant TICK_SPACING = 10;
17
+ uint256 constant TEST_ORDER_SIZE = 1e18; // Convenient test size (1 token for 18-decimal)
17
18
  SwapLimitOrdersWrapper internal wrapper;
18
19
 
19
20
  function setUp() public {
@@ -36,7 +37,7 @@ contract SwapLimitOrdersValidationTest is Test {
36
37
  bool result = wrapper.isLimitOrder(
37
38
  false, // not a coin buy
38
39
  makeAddr("testSwapper"),
39
- int128(uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE)),
40
+ int128(uint128(TEST_ORDER_SIZE)),
40
41
  params
41
42
  );
42
43
 
@@ -46,7 +47,7 @@ contract SwapLimitOrdersValidationTest is Test {
46
47
  function test_isLimitOrder_NoOrders() public {
47
48
  LimitOrderConfig memory params = _createEmptyParams(makeAddr("maker"));
48
49
 
49
- bool result = wrapper.isLimitOrder(true, makeAddr("testSwapper"), int128(uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE)), params);
50
+ bool result = wrapper.isLimitOrder(true, makeAddr("testSwapper"), int128(uint128(TEST_ORDER_SIZE)), params);
50
51
 
51
52
  assertFalse(result, "should return false when no orders configured");
52
53
  }
@@ -57,7 +58,7 @@ contract SwapLimitOrdersValidationTest is Test {
57
58
  bool result = wrapper.isLimitOrder(
58
59
  true,
59
60
  address(0), // zero swapper
60
- int128(uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE)),
61
+ int128(uint128(TEST_ORDER_SIZE)),
61
62
  params
62
63
  );
63
64
 
@@ -90,23 +91,23 @@ contract SwapLimitOrdersValidationTest is Test {
90
91
  assertFalse(result, "should return false for zero coinDelta");
91
92
  }
92
93
 
93
- function test_isLimitOrder_BelowMinimumSize() public {
94
+ function test_isLimitOrder_SmallSize() public {
94
95
  LimitOrderConfig memory params = _createValidParams(makeAddr("maker"), 1);
95
96
 
96
97
  bool result = wrapper.isLimitOrder(
97
98
  true,
98
99
  makeAddr("testSwapper"),
99
- int128(uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE - 1)), // dust amount
100
+ int128(1), // small amount
100
101
  params
101
102
  );
102
103
 
103
- assertFalse(result, "should return false for dust amounts below minimum");
104
+ assertTrue(result, "should return true for any positive amount");
104
105
  }
105
106
 
106
107
  function test_isLimitOrder_ValidCase() public {
107
108
  LimitOrderConfig memory params = _createValidParams(makeAddr("maker"), 1);
108
109
 
109
- bool result = wrapper.isLimitOrder(true, makeAddr("testSwapper"), int128(uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE)), params);
110
+ bool result = wrapper.isLimitOrder(true, makeAddr("testSwapper"), int128(uint128(TEST_ORDER_SIZE)), params);
110
111
 
111
112
  assertTrue(result, "should return true when all conditions met");
112
113
  }
@@ -180,14 +181,13 @@ contract SwapLimitOrdersValidationTest is Test {
180
181
  assertEq(totalPercent, 8000, "should allow undershoot");
181
182
  }
182
183
 
183
- function test_computeOrders_BelowMinimum() public {
184
+ function test_computeOrders_ZeroSize() public {
184
185
  LimitOrderConfig memory params = _createValidParams(makeAddr("maker"), 2);
185
- uint128 dustSize = uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE - 1);
186
186
 
187
187
  (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
188
188
  testKey,
189
189
  true, // isCurrency0
190
- uint128(dustSize),
190
+ 0, // zero size
191
191
  0, // baseTick
192
192
  TickMath.getSqrtPriceAtTick(0),
193
193
  params
@@ -196,7 +196,7 @@ contract SwapLimitOrdersValidationTest is Test {
196
196
  assertEq(orders.sizes.length, 0, "should return empty orders");
197
197
  assertEq(orders.ticks.length, 0, "should return empty ticks");
198
198
  assertEq(allocated, 0, "should have zero allocated");
199
- assertEq(unallocated, uint128(dustSize), "all should be unallocated");
199
+ assertEq(unallocated, 0, "unallocated should be zero");
200
200
  }
201
201
 
202
202
  function test_computeOrders_SkipsZeroSizeOrders() public {
@@ -218,7 +218,7 @@ contract SwapLimitOrdersValidationTest is Test {
218
218
  params.percentages[3] = 1; // 0.01% - may round to zero with small size
219
219
 
220
220
  // Use exactly MIN size which is 1e18
221
- uint128 totalSize = uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE);
221
+ uint128 totalSize = uint128(TEST_ORDER_SIZE);
222
222
 
223
223
  (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
224
224
  testKey,
@@ -229,7 +229,7 @@ contract SwapLimitOrdersValidationTest is Test {
229
229
  params
230
230
  );
231
231
 
232
- // With MIN_LIMIT_ORDER_SIZE (1e18) and 1bp = 1e14, orders should not be skipped
232
+ // With TEST_ORDER_SIZE (1e18) and 1bp = 1e14, orders should not be skipped
233
233
  // Let's just verify we get at least one order
234
234
  assertGt(orders.sizes.length, 0, "should create at least one order");
235
235
  assertEq(orders.sizes.length, orders.ticks.length, "sizes and ticks should match");
@@ -246,14 +246,7 @@ contract SwapLimitOrdersValidationTest is Test {
246
246
 
247
247
  int24 maxTick = TickMath.maxUsableTick(TICK_SPACING);
248
248
 
249
- (Orders memory orders, , ) = SwapLimitOrders.computeOrders(
250
- testKey,
251
- true,
252
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
253
- 0,
254
- TickMath.getSqrtPriceAtTick(0),
255
- params
256
- );
249
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, true, uint128(TEST_ORDER_SIZE), 0, TickMath.getSqrtPriceAtTick(0), params);
257
250
 
258
251
  assertEq(orders.ticks.length, 1, "should create one order");
259
252
  // Should clamp to max usable tick - the function applies clamping logic
@@ -279,7 +272,7 @@ contract SwapLimitOrdersValidationTest is Test {
279
272
  (Orders memory orders, , ) = SwapLimitOrders.computeOrders(
280
273
  testKey,
281
274
  false, // isCurrency0 = false means selling, inverts multiple
282
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
275
+ uint128(TEST_ORDER_SIZE),
283
276
  startTick,
284
277
  TickMath.getSqrtPriceAtTick(startTick),
285
278
  params
@@ -303,7 +296,7 @@ contract SwapLimitOrdersValidationTest is Test {
303
296
  (Orders memory orders, , ) = SwapLimitOrders.computeOrders(
304
297
  testKey,
305
298
  true, // isCurrency0
306
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
299
+ uint128(TEST_ORDER_SIZE),
307
300
  baseTick,
308
301
  TickMath.getSqrtPriceAtTick(baseTick),
309
302
  params
@@ -328,7 +321,7 @@ contract SwapLimitOrdersValidationTest is Test {
328
321
  (Orders memory orders, , ) = SwapLimitOrders.computeOrders(
329
322
  testKey,
330
323
  false, // not isCurrency0
331
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
324
+ uint128(TEST_ORDER_SIZE),
332
325
  baseTick,
333
326
  TickMath.getSqrtPriceAtTick(baseTick),
334
327
  params
@@ -354,7 +347,7 @@ contract SwapLimitOrdersValidationTest is Test {
354
347
  (Orders memory orders, , ) = SwapLimitOrders.computeOrders(
355
348
  testKey,
356
349
  false, // not isCurrency0 - triggers inversion
357
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
350
+ uint128(TEST_ORDER_SIZE),
358
351
  baseTick,
359
352
  TickMath.getSqrtPriceAtTick(baseTick),
360
353
  params
@@ -374,14 +367,7 @@ contract SwapLimitOrdersValidationTest is Test {
374
367
  params.multiples[0] = 1000000e18;
375
368
  params.percentages[0] = 10000;
376
369
 
377
- (Orders memory orders1, , ) = SwapLimitOrders.computeOrders(
378
- testKey,
379
- true,
380
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
381
- 0,
382
- TickMath.getSqrtPriceAtTick(0),
383
- params
384
- );
370
+ (Orders memory orders1, , ) = SwapLimitOrders.computeOrders(testKey, true, uint128(TEST_ORDER_SIZE), 0, TickMath.getSqrtPriceAtTick(0), params);
385
371
  assertLe(orders1.ticks[0], TickMath.maxUsableTick(TICK_SPACING), "should clamp to maxTick");
386
372
 
387
373
  // Test 2: aligned < minTick (line 168)
@@ -390,7 +376,7 @@ contract SwapLimitOrdersValidationTest is Test {
390
376
  (Orders memory orders2, , ) = SwapLimitOrders.computeOrders(
391
377
  testKey,
392
378
  false, // inverted, goes negative
393
- uint128(SwapLimitOrders.MIN_LIMIT_ORDER_SIZE),
379
+ uint128(TEST_ORDER_SIZE),
394
380
  veryHighTick,
395
381
  TickMath.getSqrtPriceAtTick(veryHighTick),
396
382
  params
@@ -14,24 +14,14 @@ contract SwapWithLimitOrdersLogicWrapper {
14
14
  return true; // Would proceed to fill
15
15
  }
16
16
 
17
- /// @notice Tests tick ordering logic for currency0 (lines 403-406)
18
- function orderTicks_currency0(int24 tickBeforeSwap, int24 tickAfterSwap) external pure returns (int24 startTick, int24 endTick) {
19
- bool isCurrency0 = true;
20
- if (isCurrency0) {
21
- // Currency0 orders need ascending tick range
22
- startTick = tickBeforeSwap < tickAfterSwap ? tickBeforeSwap : tickAfterSwap;
23
- endTick = tickBeforeSwap < tickAfterSwap ? tickAfterSwap : tickBeforeSwap;
24
- }
25
- }
26
-
27
- /// @notice Tests tick ordering logic for currency1 (lines 407-411)
28
- function orderTicks_currency1(int24 tickBeforeSwap, int24 tickAfterSwap) external pure returns (int24 startTick, int24 endTick) {
29
- bool isCurrency0 = false;
30
- if (!isCurrency0) {
31
- // Currency1 orders need descending tick range
32
- startTick = tickBeforeSwap > tickAfterSwap ? tickBeforeSwap : tickAfterSwap;
33
- endTick = tickBeforeSwap > tickAfterSwap ? tickAfterSwap : tickBeforeSwap;
17
+ /// @notice Tests _fillOrders direction derivation from tick movement
18
+ /// @return shouldFill Whether fill should proceed
19
+ /// @return isCurrency0 The derived fill direction
20
+ function deriveFillDirection(int24 tickBeforeSwap, int24 tickAfterSwap) external pure returns (bool shouldFill, bool isCurrency0) {
21
+ if (tickAfterSwap == tickBeforeSwap) {
22
+ return (false, false);
34
23
  }
24
+ return (true, tickAfterSwap > tickBeforeSwap);
35
25
  }
36
26
 
37
27
  /// @notice Tests settlement unallocated branch (line 356)
@@ -109,70 +99,24 @@ contract SwapWithLimitOrdersUnitTest is Test {
109
99
  assertTrue(shouldFill, "should fill when maxFillCount is 1");
110
100
  }
111
101
 
112
- /// @notice Tests currency0 tick ordering when tickBefore < tickAfter (ascending)
113
- function test_orderTicks_currency0_ascending() public view {
114
- int24 tickBefore = 1000;
115
- int24 tickAfter = 2000;
116
-
117
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(tickBefore, tickAfter);
118
-
119
- assertEq(startTick, 1000, "startTick should be tickBefore");
120
- assertEq(endTick, 2000, "endTick should be tickAfter");
102
+ /// @notice Tests fill direction derivation: tick increase currency0
103
+ function test_deriveFillDirection_tickIncreases_isCurrency0() public view {
104
+ (bool shouldFill, bool isCurrency0) = wrapper.deriveFillDirection(1000, 2000);
105
+ assertTrue(shouldFill, "should fill when tick moved");
106
+ assertTrue(isCurrency0, "tick increase = currency0 orders fillable");
121
107
  }
122
108
 
123
- /// @notice Tests currency0 tick ordering when tickBefore > tickAfter (needs swap)
124
- function test_orderTicks_currency0_descending_swaps() public view {
125
- int24 tickBefore = 2000;
126
- int24 tickAfter = 1000;
127
-
128
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(tickBefore, tickAfter);
129
-
130
- assertEq(startTick, 1000, "startTick should be minimum");
131
- assertEq(endTick, 2000, "endTick should be maximum");
109
+ /// @notice Tests fill direction derivation: tick decrease currency1
110
+ function test_deriveFillDirection_tickDecreases_isCurrency1() public view {
111
+ (bool shouldFill, bool isCurrency0) = wrapper.deriveFillDirection(2000, 1000);
112
+ assertTrue(shouldFill, "should fill when tick moved");
113
+ assertFalse(isCurrency0, "tick decrease = currency1 orders fillable");
132
114
  }
133
115
 
134
- /// @notice Tests currency0 tick ordering when ticks are equal
135
- function test_orderTicks_currency0_equal() public view {
136
- int24 tickBefore = 1500;
137
- int24 tickAfter = 1500;
138
-
139
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(tickBefore, tickAfter);
140
-
141
- assertEq(startTick, 1500, "startTick should equal tickBefore");
142
- assertEq(endTick, 1500, "endTick should equal tickBefore");
143
- }
144
-
145
- /// @notice Tests currency1 tick ordering when tickBefore > tickAfter (descending)
146
- function test_orderTicks_currency1_descending() public view {
147
- int24 tickBefore = 2000;
148
- int24 tickAfter = 1000;
149
-
150
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency1(tickBefore, tickAfter);
151
-
152
- assertEq(startTick, 2000, "startTick should be tickBefore");
153
- assertEq(endTick, 1000, "endTick should be tickAfter");
154
- }
155
-
156
- /// @notice Tests currency1 tick ordering when tickBefore < tickAfter (needs swap)
157
- function test_orderTicks_currency1_ascending_swaps() public view {
158
- int24 tickBefore = 1000;
159
- int24 tickAfter = 2000;
160
-
161
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency1(tickBefore, tickAfter);
162
-
163
- assertEq(startTick, 2000, "startTick should be maximum");
164
- assertEq(endTick, 1000, "endTick should be minimum");
165
- }
166
-
167
- /// @notice Tests currency1 tick ordering with negative ticks
168
- function test_orderTicks_currency1_negativeTicks() public view {
169
- int24 tickBefore = -1000;
170
- int24 tickAfter = -2000;
171
-
172
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency1(tickBefore, tickAfter);
173
-
174
- assertEq(startTick, -1000, "startTick should be -1000");
175
- assertEq(endTick, -2000, "endTick should be -2000");
116
+ /// @notice Tests fill direction derivation: no movement no fill
117
+ function test_deriveFillDirection_noMovement_noFill() public view {
118
+ (bool shouldFill, ) = wrapper.deriveFillDirection(1500, 1500);
119
+ assertFalse(shouldFill, "should not fill when tick unchanged");
176
120
  }
177
121
 
178
122
  /// @notice Tests that unallocated > 0 triggers take
@@ -302,17 +246,6 @@ contract SwapWithLimitOrdersUnitTest is Test {
302
246
  assertEq(result, "Valid");
303
247
  }
304
248
 
305
- /// @notice Tests tick ordering with max int24 values
306
- function test_orderTicks_maxValues() public view {
307
- int24 maxTick = type(int24).max;
308
- int24 minTick = type(int24).min;
309
-
310
- (int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(maxTick, minTick);
311
-
312
- assertEq(startTick, minTick, "should handle max/min correctly");
313
- assertEq(endTick, maxTick, "should handle max/min correctly");
314
- }
315
-
316
249
  /// @notice Tests unallocated with max uint128 value
317
250
  function test_shouldTakeUnallocated_maxValue() public view {
318
251
  bool shouldTake = wrapper.shouldTakeUnallocated(type(uint128).max);
@@ -26,6 +26,8 @@ import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
26
26
  import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
27
27
  import {AddressConstants} from "@zoralabs/coins/test/utils/hookmate/constants/AddressConstants.sol";
28
28
  import {ICoin} from "@zoralabs/coins/src/interfaces/ICoin.sol";
29
+ import {IWETH} from "@zoralabs/coins/src/interfaces/IWETH.sol";
30
+ import {MockWETH} from "./MockWETH.sol";
29
31
 
30
32
  /**
31
33
  * @title BaseTest
@@ -60,9 +62,13 @@ contract BaseTest is V4TestSetup, IMsgSender {
60
62
  // Deploy AccessManager with this contract as admin
61
63
  accessManager = new AccessManager(address(this));
62
64
 
65
+ if (address(weth) == address(0)) {
66
+ weth = IWETH(address(new MockWETH()));
67
+ }
68
+
63
69
  deployCodeTo(
64
70
  "TestableZoraLimitOrderBook.sol:TestableZoraLimitOrderBook",
65
- abi.encode(address(poolManager), address(factory), address(zoraHookRegistry), address(accessManager)),
71
+ abi.encode(address(poolManager), address(factory), address(zoraHookRegistry), address(accessManager), address(weth)),
66
72
  address(limitOrderBook)
67
73
  );
68
74
  require(limitOrderBook.authority() == address(accessManager), "ZoraLimitOrderBook authority is not the access manager");
@@ -96,7 +102,9 @@ contract BaseTest is V4TestSetup, IMsgSender {
96
102
  keccak256("LimitOrderFilled(address,address,address,uint128,uint128,address,uint128,bytes32,int24,bytes32)");
97
103
  bytes32 internal constant LIMIT_ORDER_UPDATED_TOPIC = keccak256("LimitOrderUpdated(address,address,bytes32,bool,int24,uint128,bytes32,bool)");
98
104
  bytes32 internal constant SWAP_WITH_LIMIT_ORDERS_EXECUTED_TOPIC =
99
- keccak256("SwapWithLimitOrdersExecuted(address,address,(address,address,uint24,int24,address),int256,int24,int24,(bytes32,uint256,uint256)[])");
105
+ keccak256(
106
+ "SwapWithLimitOrdersExecuted(address,address,(address,address,uint24,int24,address),int24,int24,int128,int128,uint160,(bytes32,uint256,uint256)[])"
107
+ );
100
108
 
101
109
  struct QueueSnapshot {
102
110
  bytes32 head;
@@ -150,9 +158,11 @@ contract BaseTest is V4TestSetup, IMsgSender {
150
158
  address sender;
151
159
  address recipient;
152
160
  PoolKey poolKey;
153
- int256 delta;
154
161
  int24 tickBefore;
155
162
  int24 tickAfter;
163
+ int128 amount0;
164
+ int128 amount1;
165
+ uint160 sqrtPriceX96;
156
166
  CreatedOrder[] orders;
157
167
  }
158
168
 
@@ -464,6 +474,10 @@ contract BaseTest is V4TestSetup, IMsgSender {
464
474
  return isCurrency0 ? baseTick + offset : baseTick - offset;
465
475
  }
466
476
 
477
+ function _fillableTick(bool isCurrency0, int24 orderTick, int24 spacing) internal pure returns (int24) {
478
+ return isCurrency0 ? orderTick + spacing : orderTick - spacing;
479
+ }
480
+
467
481
  function _buildDeterministicOrders(
468
482
  PoolKey memory key,
469
483
  bool isCurrency0,
@@ -667,18 +681,25 @@ contract BaseTest is V4TestSetup, IMsgSender {
667
681
  Vm.Log memory log = logs[i];
668
682
  if (log.topics.length == 0 || log.topics[0] != SWAP_WITH_LIMIT_ORDERS_EXECUTED_TOPIC) continue;
669
683
 
670
- (PoolKey memory poolKey, int256 delta, int24 tickBefore, int24 tickAfter, CreatedOrder[] memory orders) = abi.decode(
671
- log.data,
672
- (PoolKey, int256, int24, int24, CreatedOrder[])
673
- );
684
+ (
685
+ PoolKey memory poolKey,
686
+ int24 tickBefore,
687
+ int24 tickAfter,
688
+ int128 amount0,
689
+ int128 amount1,
690
+ uint160 sqrtPriceX96,
691
+ CreatedOrder[] memory orders
692
+ ) = abi.decode(log.data, (PoolKey, int24, int24, int128, int128, uint160, CreatedOrder[]));
674
693
 
675
694
  swaps[idx] = SwapExecutedLog({
676
695
  sender: address(uint160(uint256(log.topics[1]))),
677
696
  recipient: address(uint160(uint256(log.topics[2]))),
678
697
  poolKey: poolKey,
679
- delta: delta,
680
698
  tickBefore: tickBefore,
681
699
  tickAfter: tickAfter,
700
+ amount0: amount0,
701
+ amount1: amount1,
702
+ sqrtPriceX96: sqrtPriceX96,
682
703
  orders: orders
683
704
  });
684
705
  ++idx;
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+ import {IWETH} from "@zoralabs/coins/src/interfaces/IWETH.sol";
6
+
7
+ contract MockWETH is IWETH, ERC20 {
8
+ constructor() ERC20("WETH", "WETH") {}
9
+
10
+ function approve(address spender, uint256 value) public override(ERC20, IWETH) returns (bool) {
11
+ return super.approve(spender, value);
12
+ }
13
+
14
+ function transfer(address to, uint256 value) public override(ERC20, IWETH) returns (bool) {
15
+ return super.transfer(to, value);
16
+ }
17
+
18
+ function transferFrom(address from, address to, uint256 value) public override(ERC20, IWETH) returns (bool) {
19
+ return super.transferFrom(from, to, value);
20
+ }
21
+
22
+ function balanceOf(address account) public view override(ERC20, IWETH) returns (uint256) {
23
+ return super.balanceOf(account);
24
+ }
25
+
26
+ function deposit() external payable {
27
+ _mint(msg.sender, msg.value);
28
+ }
29
+
30
+ function withdraw(uint256 wad) external {
31
+ _burn(msg.sender, wad);
32
+ (bool ok, ) = msg.sender.call{value: wad}("");
33
+ require(ok, "WETH withdraw failed");
34
+ }
35
+
36
+ receive() external payable {
37
+ _mint(msg.sender, msg.value);
38
+ }
39
+ }
@@ -4,7 +4,7 @@ pragma solidity ^0.8.28;
4
4
  import {ZoraLimitOrderBook} from "../../src/ZoraLimitOrderBook.sol";
5
5
  import {LimitOrderTypes} from "../../src/libs/LimitOrderTypes.sol";
6
6
  import {LimitOrderStorage} from "../../src/libs/LimitOrderStorage.sol";
7
- import {LimitOrderFill} from "../../src/libs/LimitOrderFill.sol";
7
+ import {LimitOrderViews} from "../../src/libs/LimitOrderViews.sol";
8
8
  import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
9
9
 
10
10
  contract TestableZoraLimitOrderBook is ZoraLimitOrderBook {
@@ -12,8 +12,9 @@ contract TestableZoraLimitOrderBook is ZoraLimitOrderBook {
12
12
  address poolManager_,
13
13
  address zoraCoinVersionLookup_,
14
14
  address zoraHookRegistry_,
15
- address authority_
16
- ) ZoraLimitOrderBook(poolManager_, zoraCoinVersionLookup_, zoraHookRegistry_, authority_) {}
15
+ address authority_,
16
+ address weth_
17
+ ) ZoraLimitOrderBook(poolManager_, zoraCoinVersionLookup_, zoraHookRegistry_, authority_, weth_) {}
17
18
 
18
19
  function exposedTickQueue(bytes32 poolKeyHash, address coin, int24 tick) external view returns (LimitOrderTypes.Queue memory) {
19
20
  return getTickQueue(poolKeyHash, coin, tick);
@@ -38,10 +39,7 @@ contract TestableZoraLimitOrderBook is ZoraLimitOrderBook {
38
39
  int24 endTick
39
40
  ) external view returns (int24 resolvedStart, int24 resolvedEnd) {
40
41
  LimitOrderStorage.Layout storage state = LimitOrderStorage.layout();
41
- LimitOrderFill.Context memory ctx;
42
- ctx.poolManager = poolManager;
43
- ctx.versionLookup = zoraCoinVersionLookup;
44
- (, resolvedStart, resolvedEnd) = LimitOrderFill.validateTickRange(state, ctx, key, isCurrency0, startTick, endTick);
42
+ (, resolvedStart, resolvedEnd) = LimitOrderViews.validateTickRange(state, poolManager, key, isCurrency0, startTick, endTick);
45
43
  }
46
44
 
47
45
  function exposedOrder(bytes32 orderId) external view returns (LimitOrderTypes.LimitOrder memory) {