@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.
- package/.turbo/turbo-build$colon$js.log +47 -45
- package/CHANGELOG.md +61 -0
- package/abis/IWETH.json +118 -0
- package/abis/IZoraLimitOrderBook.json +5 -0
- package/abis/LimitOrderLiquidity.json +7 -0
- package/abis/LimitOrderViews.json +62 -0
- package/abis/SwapWithLimitOrders.json +18 -11
- package/abis/ZoraLimitOrderBook.json +28 -0
- package/cache/solidity-files-cache.json +1 -1
- package/dist/index.cjs +29 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +37 -9
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/out/BytesLib.sol/BytesLib.json +1 -1
- package/out/CoinCommon.sol/CoinCommon.json +1 -1
- package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -1
- package/out/CoinConstants.sol/CoinConstants.json +1 -1
- package/out/DopplerMath.sol/DopplerMath.json +1 -1
- package/out/FixedPoint96.sol/FixedPoint96.json +1 -1
- package/out/ISwapRouter.sol/ISwapRouter.json +1 -1
- package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -1
- package/out/IWETH.sol/IWETH.json +1 -0
- package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -1
- package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -1
- package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -1
- package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -1
- package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -1
- package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -1
- package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -1
- package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -1
- package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -1
- package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -1
- package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -1
- package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -1
- package/out/LimitOrderViews.sol/LimitOrderViews.json +1 -0
- package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -1
- package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -1
- package/out/Path.sol/Path.json +1 -1
- package/out/Permit2Payments.sol/Permit2Payments.json +1 -1
- package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +1 -1
- package/out/SimpleAccessManager.sol/SimpleAccessManager.json +1 -1
- package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -1
- package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -1
- package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -1
- package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -1
- package/out/UnsafeMath.sol/UnsafeMath.json +1 -1
- package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -1
- package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -1
- package/out/build-info/{69718f10d1dc37f0.json → 876cc09bc44cc8a7.json} +1 -1
- package/out/uniswap/BitMath.sol/BitMath.json +1 -1
- package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -1
- package/out/uniswap/FullMath.sol/FullMath.json +1 -1
- package/out/uniswap/SafeCast.sol/SafeCast.json +1 -1
- package/out/uniswap/TickMath.sol/TickMath.json +1 -1
- package/package/wagmiGenerated.ts +28 -7
- package/package.json +1 -1
- package/src/IZoraLimitOrderBook.sol +2 -0
- package/src/ZoraLimitOrderBook.sol +22 -8
- package/src/libs/LimitOrderBitmap.sol +0 -51
- package/src/libs/LimitOrderCommon.sol +48 -30
- package/src/libs/LimitOrderCreate.sol +5 -18
- package/src/libs/LimitOrderFill.sol +32 -161
- package/src/libs/LimitOrderLiquidity.sol +92 -71
- package/src/libs/LimitOrderViews.sol +168 -0
- package/src/libs/LimitOrderWithdraw.sol +13 -4
- package/src/libs/SwapLimitOrders.sol +14 -7
- package/src/router/SwapWithLimitOrders.sol +40 -26
- package/test/LimitOrderBitmap.t.sol +13 -7
- package/test/LimitOrderFill.t.sol +43 -0
- package/test/LimitOrderLibraries.t.sol +18 -10
- package/test/LimitOrderLiquidityPayouts.t.sol +280 -3
- package/test/LimitOrderWithdraw.t.sol +28 -1
- package/test/SwapWithLimitOrders.t.sol +3 -3
- package/test/SwapWithLimitOrdersRouter.t.sol +108 -11
- package/test/unit/LimitOrderBitmapUnit.t.sol +0 -134
- package/test/unit/LimitOrderCreateUnit.t.sol +32 -0
- package/test/unit/SwapLimitOrdersUnit.t.sol +231 -33
- package/test/unit/SwapLimitOrdersValidation.t.sol +20 -34
- package/test/unit/SwapWithLimitOrdersUnit.t.sol +21 -88
- package/test/utils/BaseTest.sol +29 -8
- package/test/utils/MockWETH.sol +39 -0
- package/test/utils/TestableZoraLimitOrderBook.sol +5 -7
|
@@ -82,140 +82,6 @@ contract LimitOrderBitmapUnitTest is Test {
|
|
|
82
82
|
assertTrue(_isTickSet(tick), "bit should remain set when sizeAfter > 0");
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
/// @notice Tests getExecutableTicks with zeroForOne = true (downward price movement)
|
|
86
|
-
function test_getExecutableTicks_zeroForOne_findsInitializedTicks() public {
|
|
87
|
-
// Set up ticks: 10000, 10200, 10400 (spaced by TICK_SPACING)
|
|
88
|
-
int24 tick1 = 10000;
|
|
89
|
-
int24 tick2 = 10200;
|
|
90
|
-
int24 tick3 = 10400;
|
|
91
|
-
|
|
92
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick1, TICK_SPACING, 0);
|
|
93
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick2, TICK_SPACING, 0);
|
|
94
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick3, TICK_SPACING, 0);
|
|
95
|
-
|
|
96
|
-
// Set queue lengths to non-zero (simulates orders exist)
|
|
97
|
-
poolQueue[tick1].length = 1;
|
|
98
|
-
poolQueue[tick2].length = 1;
|
|
99
|
-
poolQueue[tick3].length = 1;
|
|
100
|
-
|
|
101
|
-
// Swap from 10800 down to 9800 (crosses all three ticks)
|
|
102
|
-
int24 tickBefore = 10800;
|
|
103
|
-
int24 tickAfter = 9800;
|
|
104
|
-
bool zeroForOne = true;
|
|
105
|
-
|
|
106
|
-
int24[] memory executableTicks = LimitOrderBitmap.getExecutableTicks(bitmap, poolQueue, TICK_SPACING, zeroForOne, tickBefore, tickAfter);
|
|
107
|
-
|
|
108
|
-
// Should find all 3 initialized ticks
|
|
109
|
-
assertEq(executableTicks.length, 3, "should find 3 executable ticks");
|
|
110
|
-
assertEq(executableTicks[0], tick3, "should find tick3 first (highest)");
|
|
111
|
-
assertEq(executableTicks[1], tick2, "should find tick2 second");
|
|
112
|
-
assertEq(executableTicks[2], tick1, "should find tick1 last (lowest)");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/// @notice Tests getExecutableTicks with zeroForOne = false (upward price movement)
|
|
116
|
-
function test_getExecutableTicks_oneForZero_findsInitializedTicks() public {
|
|
117
|
-
// Set up ticks: 5000, 5200, 5400
|
|
118
|
-
int24 tick1 = 5000;
|
|
119
|
-
int24 tick2 = 5200;
|
|
120
|
-
int24 tick3 = 5400;
|
|
121
|
-
|
|
122
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick1, TICK_SPACING, 0);
|
|
123
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick2, TICK_SPACING, 0);
|
|
124
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick3, TICK_SPACING, 0);
|
|
125
|
-
|
|
126
|
-
poolQueue[tick1].length = 1;
|
|
127
|
-
poolQueue[tick2].length = 1;
|
|
128
|
-
poolQueue[tick3].length = 1;
|
|
129
|
-
|
|
130
|
-
// Swap from 4800 up to 5600 (crosses all three ticks)
|
|
131
|
-
int24 tickBefore = 4800;
|
|
132
|
-
int24 tickAfter = 5600;
|
|
133
|
-
bool zeroForOne = false;
|
|
134
|
-
|
|
135
|
-
int24[] memory executableTicks = LimitOrderBitmap.getExecutableTicks(bitmap, poolQueue, TICK_SPACING, zeroForOne, tickBefore, tickAfter);
|
|
136
|
-
|
|
137
|
-
// Should find all 3 initialized ticks in ascending order
|
|
138
|
-
assertEq(executableTicks.length, 3, "should find 3 executable ticks");
|
|
139
|
-
assertEq(executableTicks[0], tick1, "should find tick1 first (lowest)");
|
|
140
|
-
assertEq(executableTicks[1], tick2, "should find tick2 second");
|
|
141
|
-
assertEq(executableTicks[2], tick3, "should find tick3 last (highest)");
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/// @notice Tests getExecutableTicks skips ticks with empty queues
|
|
145
|
-
function test_getExecutableTicks_skipsEmptyQueues() public {
|
|
146
|
-
// Set up 3 ticks, but only 2 have orders
|
|
147
|
-
int24 tick1 = 6000;
|
|
148
|
-
int24 tick2 = 6200; // This one will have empty queue
|
|
149
|
-
int24 tick3 = 6400;
|
|
150
|
-
|
|
151
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick1, TICK_SPACING, 0);
|
|
152
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick2, TICK_SPACING, 0);
|
|
153
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick3, TICK_SPACING, 0);
|
|
154
|
-
|
|
155
|
-
poolQueue[tick1].length = 1;
|
|
156
|
-
poolQueue[tick2].length = 0; // Empty queue - should skip
|
|
157
|
-
poolQueue[tick3].length = 1;
|
|
158
|
-
|
|
159
|
-
int24 tickBefore = 6600;
|
|
160
|
-
int24 tickAfter = 5800;
|
|
161
|
-
bool zeroForOne = true;
|
|
162
|
-
|
|
163
|
-
int24[] memory executableTicks = LimitOrderBitmap.getExecutableTicks(bitmap, poolQueue, TICK_SPACING, zeroForOne, tickBefore, tickAfter);
|
|
164
|
-
|
|
165
|
-
// Should find only 2 ticks (skip tick2 with empty queue)
|
|
166
|
-
assertEq(executableTicks.length, 2, "should find only 2 executable ticks");
|
|
167
|
-
assertEq(executableTicks[0], tick3, "should find tick3");
|
|
168
|
-
assertEq(executableTicks[1], tick1, "should find tick1");
|
|
169
|
-
// tick2 should not be in the array
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/// @notice Tests getExecutableTicks with no movement (tickBefore == tickAfter)
|
|
173
|
-
function test_getExecutableTicks_noMovement_returnsEmpty() public {
|
|
174
|
-
int24 tick = 7000;
|
|
175
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick, TICK_SPACING, 0);
|
|
176
|
-
poolQueue[tick].length = 1;
|
|
177
|
-
|
|
178
|
-
int24 tickBefore = 7000;
|
|
179
|
-
int24 tickAfter = 7000; // No movement
|
|
180
|
-
bool zeroForOne = true;
|
|
181
|
-
|
|
182
|
-
int24[] memory executableTicks = LimitOrderBitmap.getExecutableTicks(bitmap, poolQueue, TICK_SPACING, zeroForOne, tickBefore, tickAfter);
|
|
183
|
-
|
|
184
|
-
// Should return empty array (no ticks crossed)
|
|
185
|
-
assertEq(executableTicks.length, 0, "should return empty array for no movement");
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/// @notice Tests getExecutableTicks stops at target even if more ticks initialized beyond
|
|
189
|
-
function test_getExecutableTicks_stopsAtTarget() public {
|
|
190
|
-
// Set up ticks: 8000, 8200, 8400, 8600
|
|
191
|
-
int24 tick1 = 8000;
|
|
192
|
-
int24 tick2 = 8200;
|
|
193
|
-
int24 tick3 = 8400;
|
|
194
|
-
int24 tick4 = 8600;
|
|
195
|
-
|
|
196
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick1, TICK_SPACING, 0);
|
|
197
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick2, TICK_SPACING, 0);
|
|
198
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick3, TICK_SPACING, 0);
|
|
199
|
-
LimitOrderBitmap.setIfFirst(bitmap, tick4, TICK_SPACING, 0);
|
|
200
|
-
|
|
201
|
-
poolQueue[tick1].length = 1;
|
|
202
|
-
poolQueue[tick2].length = 1;
|
|
203
|
-
poolQueue[tick3].length = 1;
|
|
204
|
-
poolQueue[tick4].length = 1;
|
|
205
|
-
|
|
206
|
-
// Swap only crosses tick4 and tick3, stops before tick2
|
|
207
|
-
int24 tickBefore = 8800;
|
|
208
|
-
int24 tickAfter = 8300; // Stops between tick3 and tick2
|
|
209
|
-
bool zeroForOne = true;
|
|
210
|
-
|
|
211
|
-
int24[] memory executableTicks = LimitOrderBitmap.getExecutableTicks(bitmap, poolQueue, TICK_SPACING, zeroForOne, tickBefore, tickAfter);
|
|
212
|
-
|
|
213
|
-
// Should find only tick4 and tick3 (stops at target)
|
|
214
|
-
assertEq(executableTicks.length, 2, "should find only 2 ticks before target");
|
|
215
|
-
assertEq(executableTicks[0], tick4, "should find tick4");
|
|
216
|
-
assertEq(executableTicks[1], tick3, "should find tick3");
|
|
217
|
-
}
|
|
218
|
-
|
|
219
85
|
/// @notice Tests word boundaries (ticks at 256 * spacing intervals)
|
|
220
86
|
function test_setIfFirst_wordBoundary() public {
|
|
221
87
|
// Ticks at word boundaries
|
|
@@ -73,6 +73,24 @@ contract LimitOrderCreateWrapper {
|
|
|
73
73
|
refunded = requestedSize - realizedSize;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
/// @notice Generates orderId using abi.encode (matches getOrderId)
|
|
78
|
+
function getOrderId(bytes32 poolKeyHash, address coin, int24 tick, address maker, uint256 nonce) external pure returns (bytes32) {
|
|
79
|
+
return keccak256(abi.encode(poolKeyHash, coin, tick, maker, nonce));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// @notice Generates orderId using assembly (matches _generateOrderId in LimitOrderCreate.sol)
|
|
83
|
+
function generateOrderIdAssembly(bytes32 poolKeyHash, address coin, int24 orderTick, address maker, uint256 nonce) external pure returns (bytes32 orderId) {
|
|
84
|
+
assembly ("memory-safe") {
|
|
85
|
+
let ptr := mload(0x40)
|
|
86
|
+
mstore(ptr, poolKeyHash)
|
|
87
|
+
mstore(add(ptr, 0x20), coin)
|
|
88
|
+
mstore(add(ptr, 0x40), orderTick)
|
|
89
|
+
mstore(add(ptr, 0x60), maker)
|
|
90
|
+
mstore(add(ptr, 0x80), nonce)
|
|
91
|
+
orderId := keccak256(ptr, 0xa0)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
76
94
|
}
|
|
77
95
|
|
|
78
96
|
/// @notice Direct unit tests for LimitOrderCreate library functions
|
|
@@ -355,4 +373,18 @@ contract LimitOrderCreateUnitTest is Test {
|
|
|
355
373
|
uint128 realizedSize = wrapper.calculateRealizedSize(isCurrency0, amount0, amount1);
|
|
356
374
|
assertEq(realizedSize, 1000000000, "should handle large negative value");
|
|
357
375
|
}
|
|
376
|
+
|
|
377
|
+
/// @notice Verifies getOrderId and _generateOrderId produce identical hashes
|
|
378
|
+
function test_orderId_abiEncodeMatches() public view {
|
|
379
|
+
bytes32 poolKeyHash = keccak256("test-pool");
|
|
380
|
+
address coin = address(0x1234567890123456789012345678901234567890);
|
|
381
|
+
int24 tick = -12345;
|
|
382
|
+
address maker = address(0xabCDeF0123456789AbcdEf0123456789aBCDEF01);
|
|
383
|
+
uint256 nonce = 42;
|
|
384
|
+
|
|
385
|
+
bytes32 fromAbiEncode = wrapper.getOrderId(poolKeyHash, coin, tick, maker, nonce);
|
|
386
|
+
bytes32 fromAssembly = wrapper.generateOrderIdAssembly(poolKeyHash, coin, tick, maker, nonce);
|
|
387
|
+
|
|
388
|
+
assertEq(fromAbiEncode, fromAssembly, "orderId derivation must match");
|
|
389
|
+
}
|
|
358
390
|
}
|
|
@@ -32,8 +32,8 @@ contract SwapLimitOrdersWrapper {
|
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Must be positive
|
|
36
|
-
return coinDelta > 0
|
|
35
|
+
// Must be positive
|
|
36
|
+
return coinDelta > 0;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -44,7 +44,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
44
44
|
int24 constant TICK_SPACING = 200;
|
|
45
45
|
uint256 constant MULTIPLE_SCALE = 1e18;
|
|
46
46
|
uint256 constant PERCENT_SCALE = 10_000;
|
|
47
|
-
uint256 constant
|
|
47
|
+
uint256 constant TEST_ORDER_SIZE = 1e18; // Convenient test size (1 token for 18-decimal)
|
|
48
48
|
|
|
49
49
|
PoolKey internal testKey;
|
|
50
50
|
SwapLimitOrdersWrapper internal wrapper;
|
|
@@ -202,8 +202,8 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
202
202
|
assertEq(totalPercent, 10000, "total percent should be 10000");
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
/// @notice Tests computeOrders with totalSize
|
|
206
|
-
function
|
|
205
|
+
/// @notice Tests computeOrders with totalSize of zero returns empty
|
|
206
|
+
function test_computeOrders_zeroSize_returnsEmpty() public {
|
|
207
207
|
LimitOrderConfig memory params;
|
|
208
208
|
params.multiples = new uint256[](2);
|
|
209
209
|
params.percentages = new uint256[](2);
|
|
@@ -212,7 +212,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
212
212
|
params.percentages[0] = 5000;
|
|
213
213
|
params.percentages[1] = 5000;
|
|
214
214
|
|
|
215
|
-
uint128 totalSize =
|
|
215
|
+
uint128 totalSize = 0;
|
|
216
216
|
int24 baseTick = 0;
|
|
217
217
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
218
218
|
|
|
@@ -229,11 +229,11 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
229
229
|
assertEq(orders.sizes.length, 0, "sizes should be empty");
|
|
230
230
|
assertEq(orders.ticks.length, 0, "ticks should be empty");
|
|
231
231
|
assertEq(allocated, 0, "allocated should be 0");
|
|
232
|
-
assertEq(unallocated,
|
|
232
|
+
assertEq(unallocated, 0, "unallocated should be 0");
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
/// @notice Tests computeOrders with totalSize
|
|
236
|
-
function
|
|
235
|
+
/// @notice Tests computeOrders with small totalSize creates orders
|
|
236
|
+
function test_computeOrders_smallSize_createsOrders() public {
|
|
237
237
|
LimitOrderConfig memory params;
|
|
238
238
|
params.multiples = new uint256[](2);
|
|
239
239
|
params.percentages = new uint256[](2);
|
|
@@ -242,7 +242,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
242
242
|
params.percentages[0] = 5000;
|
|
243
243
|
params.percentages[1] = 5000;
|
|
244
244
|
|
|
245
|
-
uint128 totalSize = uint128(
|
|
245
|
+
uint128 totalSize = uint128(TEST_ORDER_SIZE); // Exactly at minimum
|
|
246
246
|
int24 baseTick = 0;
|
|
247
247
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
248
248
|
|
|
@@ -262,7 +262,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
/// @notice Tests computeOrders with multiple orders (verifying skip logic exists even if hard to trigger)
|
|
265
|
-
/// @dev Note: Zero-rounding skip is virtually impossible with
|
|
265
|
+
/// @dev Note: Zero-rounding skip is virtually impossible with reasonable sizes and PERCENT_SCALE=10000
|
|
266
266
|
/// since even 1 basis point of 1e18 = 1e14. The skip logic exists for safety in edge cases.
|
|
267
267
|
function test_computeOrders_multipleOrders_createsAll() public {
|
|
268
268
|
LimitOrderConfig memory params;
|
|
@@ -273,7 +273,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
273
273
|
params.percentages[0] = 5000;
|
|
274
274
|
params.percentages[1] = 5000;
|
|
275
275
|
|
|
276
|
-
uint128 totalSize = uint128(
|
|
276
|
+
uint128 totalSize = uint128(TEST_ORDER_SIZE * 10);
|
|
277
277
|
int24 baseTick = 0;
|
|
278
278
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
279
279
|
|
|
@@ -302,7 +302,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
302
302
|
params.percentages[i] = 1000; // 10% each (60% total)
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
uint128 totalSize = uint128(
|
|
305
|
+
uint128 totalSize = uint128(TEST_ORDER_SIZE * 100);
|
|
306
306
|
int24 baseTick = 0;
|
|
307
307
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
308
308
|
|
|
@@ -328,7 +328,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
328
328
|
params.multiples[0] = 2 * MULTIPLE_SCALE;
|
|
329
329
|
params.percentages[0] = 10000;
|
|
330
330
|
|
|
331
|
-
uint128 totalSize = uint128(
|
|
331
|
+
uint128 totalSize = uint128(TEST_ORDER_SIZE * 10);
|
|
332
332
|
int24 baseTick = 0;
|
|
333
333
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
334
334
|
|
|
@@ -355,7 +355,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
355
355
|
params.percentages[0] = 6000; // 60%
|
|
356
356
|
params.percentages[1] = 3000; // 30% (total 90%)
|
|
357
357
|
|
|
358
|
-
uint128 totalSize = uint128(1000 *
|
|
358
|
+
uint128 totalSize = uint128(1000 * TEST_ORDER_SIZE);
|
|
359
359
|
int24 baseTick = 0;
|
|
360
360
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
361
361
|
|
|
@@ -392,7 +392,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
392
392
|
params.percentages[1] = 2000; // 20% of remaining
|
|
393
393
|
params.percentages[2] = 2000; // 20% of remaining
|
|
394
394
|
|
|
395
|
-
uint128 totalSize = uint128(100 *
|
|
395
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE); // 100 units for easy math
|
|
396
396
|
int24 baseTick = 0;
|
|
397
397
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
398
398
|
|
|
@@ -430,7 +430,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
430
430
|
params.multiples[0] = 1000 * MULTIPLE_SCALE; // 1000x - extremely high
|
|
431
431
|
params.percentages[0] = 10000; // 100%
|
|
432
432
|
|
|
433
|
-
uint128 totalSize = uint128(100 *
|
|
433
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
434
434
|
int24 baseTick = 0;
|
|
435
435
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
436
436
|
|
|
@@ -453,7 +453,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
453
453
|
params.percentages[0] = 5000;
|
|
454
454
|
params.percentages[1] = 5000;
|
|
455
455
|
|
|
456
|
-
uint128 totalSize = uint128(100 *
|
|
456
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
457
457
|
int24 baseTick = 10000;
|
|
458
458
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
459
459
|
|
|
@@ -474,7 +474,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
474
474
|
params.multiples[0] = 1000000 * MULTIPLE_SCALE; // 1,000,000x
|
|
475
475
|
params.percentages[0] = 10000;
|
|
476
476
|
|
|
477
|
-
uint128 totalSize = uint128(100 *
|
|
477
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
478
478
|
// Use moderate base tick (TickMath has max/min around ±887272)
|
|
479
479
|
int24 baseTick = 100000; // Moderate positive tick
|
|
480
480
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
@@ -494,7 +494,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
494
494
|
params.multiples[0] = 2 * MULTIPLE_SCALE;
|
|
495
495
|
params.percentages[0] = 10000;
|
|
496
496
|
|
|
497
|
-
uint128 totalSize = uint128(100 *
|
|
497
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
498
498
|
// Use moderate negative base tick for currency1
|
|
499
499
|
int24 baseTick = -100000; // Moderate negative tick
|
|
500
500
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
@@ -515,7 +515,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
515
515
|
params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 100); // 1.01x
|
|
516
516
|
params.percentages[0] = 10000;
|
|
517
517
|
|
|
518
|
-
uint128 totalSize = uint128(100 *
|
|
518
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
519
519
|
int24 baseTick = 0;
|
|
520
520
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
521
521
|
|
|
@@ -534,7 +534,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
534
534
|
params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 100); // 1.01x
|
|
535
535
|
params.percentages[0] = 10000;
|
|
536
536
|
|
|
537
|
-
uint128 totalSize = uint128(100 *
|
|
537
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
538
538
|
int24 baseTick = 0;
|
|
539
539
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
540
540
|
|
|
@@ -553,7 +553,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
553
553
|
params.multiples[0] = 0; // Zero multiple - should revert in _sqrtMultiple
|
|
554
554
|
params.percentages[0] = 10000;
|
|
555
555
|
|
|
556
|
-
uint128 totalSize = uint128(100 *
|
|
556
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
557
557
|
int24 baseTick = 0;
|
|
558
558
|
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
559
559
|
|
|
@@ -571,7 +571,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
571
571
|
|
|
572
572
|
bool isCoinBuy = false; // NOT isCoinBuy - tests first branch
|
|
573
573
|
address swapper = address(0x1234);
|
|
574
|
-
int128 coinDelta = int128(int256(
|
|
574
|
+
int128 coinDelta = int128(int256(TEST_ORDER_SIZE * 2));
|
|
575
575
|
|
|
576
576
|
assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when not coin buy");
|
|
577
577
|
}
|
|
@@ -584,7 +584,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
584
584
|
|
|
585
585
|
bool isCoinBuy = true; // Pass first condition
|
|
586
586
|
address swapper = address(0x1234);
|
|
587
|
-
int128 coinDelta = int128(int256(
|
|
587
|
+
int128 coinDelta = int128(int256(TEST_ORDER_SIZE * 2));
|
|
588
588
|
|
|
589
589
|
assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when no orders");
|
|
590
590
|
}
|
|
@@ -597,8 +597,8 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
597
597
|
|
|
598
598
|
bool isCoinBuy = true;
|
|
599
599
|
address swapper = address(0x1234);
|
|
600
|
-
// casting to 'int256' is safe because
|
|
601
|
-
int128 coinDelta = int128(int256(
|
|
600
|
+
// casting to 'int256' is safe because TEST_ORDER_SIZE will not overflow int128
|
|
601
|
+
int128 coinDelta = int128(int256(TEST_ORDER_SIZE * 2));
|
|
602
602
|
|
|
603
603
|
assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when no orders");
|
|
604
604
|
}
|
|
@@ -611,7 +611,7 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
611
611
|
|
|
612
612
|
bool isCoinBuy = true;
|
|
613
613
|
address swapper = address(0); // Zero address
|
|
614
|
-
int128 coinDelta = int128(int256(
|
|
614
|
+
int128 coinDelta = int128(int256(TEST_ORDER_SIZE * 2));
|
|
615
615
|
|
|
616
616
|
assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when swapper is zero");
|
|
617
617
|
}
|
|
@@ -642,17 +642,17 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
642
642
|
assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false for zero delta");
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
-
/// @notice Tests isLimitOrder
|
|
646
|
-
function
|
|
645
|
+
/// @notice Tests isLimitOrder accepts any positive coinDelta
|
|
646
|
+
function test_isLimitOrder_smallSize_returnsTrue() public {
|
|
647
647
|
LimitOrderConfig memory params;
|
|
648
648
|
params.multiples = new uint256[](1);
|
|
649
649
|
params.percentages = new uint256[](1);
|
|
650
650
|
|
|
651
651
|
bool isCoinBuy = true;
|
|
652
652
|
address swapper = address(0x1234);
|
|
653
|
-
int128 coinDelta =
|
|
653
|
+
int128 coinDelta = 1; // Small positive amount
|
|
654
654
|
|
|
655
|
-
|
|
655
|
+
assertTrue(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return true for any positive amount");
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
/// @notice Tests isLimitOrder when all conditions are met (success case)
|
|
@@ -665,8 +665,206 @@ contract SwapLimitOrdersUnitTest is Test {
|
|
|
665
665
|
|
|
666
666
|
bool isCoinBuy = true;
|
|
667
667
|
address swapper = address(0x1234);
|
|
668
|
-
int128 coinDelta = int128(int256(
|
|
668
|
+
int128 coinDelta = int128(int256(TEST_ORDER_SIZE * 2));
|
|
669
669
|
|
|
670
670
|
assertTrue(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return true when all conditions met");
|
|
671
671
|
}
|
|
672
|
+
|
|
673
|
+
/// @notice Tests computeOrders with misaligned baseTick produces aligned output ticks
|
|
674
|
+
/// @dev This test verifies the fix for MKT-24: tick misalignment in minAway calculation
|
|
675
|
+
function test_computeOrders_misalignedBaseTick_producesValidTicks() public {
|
|
676
|
+
// Use a pool with tickSpacing = 10 for easier verification
|
|
677
|
+
PoolKey memory smallSpacingKey = PoolKey({
|
|
678
|
+
currency0: Currency.wrap(address(0x1000)),
|
|
679
|
+
currency1: Currency.wrap(address(0x2000)),
|
|
680
|
+
fee: 3000,
|
|
681
|
+
tickSpacing: 10, // Small tick spacing to make misalignment easier to reproduce
|
|
682
|
+
hooks: IHooks(address(0))
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
LimitOrderConfig memory params;
|
|
686
|
+
params.multiples = new uint256[](1);
|
|
687
|
+
params.percentages = new uint256[](1);
|
|
688
|
+
// Use small multiple that would normally produce tick close to base
|
|
689
|
+
params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 100); // 1.01x
|
|
690
|
+
params.percentages[0] = 10000;
|
|
691
|
+
|
|
692
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
693
|
+
|
|
694
|
+
// Use a baseTick that is NOT aligned to tickSpacing=10
|
|
695
|
+
int24 baseTick = 205; // Not divisible by 10 - misaligned
|
|
696
|
+
uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
|
|
697
|
+
|
|
698
|
+
// Test for currency0 (buy orders, tick should be >= baseTick + tickSpacing)
|
|
699
|
+
(Orders memory orders, , ) = SwapLimitOrders.computeOrders(
|
|
700
|
+
smallSpacingKey,
|
|
701
|
+
true, // isCurrency0
|
|
702
|
+
totalSize,
|
|
703
|
+
baseTick,
|
|
704
|
+
sqrtPriceX96,
|
|
705
|
+
params
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
// Verify the returned tick is aligned to tickSpacing
|
|
709
|
+
assertEq(orders.ticks[0] % 10, 0, "tick must be aligned to tick spacing of 10");
|
|
710
|
+
|
|
711
|
+
// Verify tick is at least one tickSpacing away from the aligned baseTick
|
|
712
|
+
// For currency0, baseTick=205 should align down to 200, so minAway=210
|
|
713
|
+
assertGe(orders.ticks[0], 210, "tick should be >= aligned baseTick (200) + spacing (10)");
|
|
714
|
+
|
|
715
|
+
// Test for currency1 (sell orders, tick should be <= baseTick - tickSpacing)
|
|
716
|
+
(Orders memory orders1, , ) = SwapLimitOrders.computeOrders(
|
|
717
|
+
smallSpacingKey,
|
|
718
|
+
false, // !isCurrency0
|
|
719
|
+
totalSize,
|
|
720
|
+
baseTick,
|
|
721
|
+
sqrtPriceX96,
|
|
722
|
+
params
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
// Verify the returned tick is aligned to tickSpacing
|
|
726
|
+
assertEq(orders1.ticks[0] % 10, 0, "tick must be aligned to tick spacing of 10");
|
|
727
|
+
|
|
728
|
+
// Verify tick is at least one tickSpacing away from the aligned baseTick
|
|
729
|
+
// For currency1, baseTick=205 should align up to 210, so minAway=200
|
|
730
|
+
assertLe(orders1.ticks[0], 200, "tick should be <= aligned baseTick (210) - spacing (10)");
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/// @notice Tests computeOrders with various misaligned baseTicks and tick spacings
|
|
734
|
+
function test_computeOrders_variousMisalignments_allProduceValidTicks() public {
|
|
735
|
+
LimitOrderConfig memory params;
|
|
736
|
+
params.multiples = new uint256[](1);
|
|
737
|
+
params.percentages = new uint256[](1);
|
|
738
|
+
params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 50); // 1.02x
|
|
739
|
+
params.percentages[0] = 10000;
|
|
740
|
+
|
|
741
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
742
|
+
|
|
743
|
+
// Test case 1: baseTick=205, tickSpacing=10
|
|
744
|
+
PoolKey memory key10 = testKey;
|
|
745
|
+
key10.tickSpacing = 10;
|
|
746
|
+
int24 baseTick1 = 205;
|
|
747
|
+
uint160 sqrtPrice1 = TickMath.getSqrtPriceAtTick(baseTick1);
|
|
748
|
+
(Orders memory orders1, , ) = SwapLimitOrders.computeOrders(key10, true, totalSize, baseTick1, sqrtPrice1, params);
|
|
749
|
+
assertEq(orders1.ticks[0] % 10, 0, "case 1: tick must be aligned to spacing 10");
|
|
750
|
+
|
|
751
|
+
// Test case 2: baseTick=1505, tickSpacing=200
|
|
752
|
+
PoolKey memory key200 = testKey;
|
|
753
|
+
key200.tickSpacing = 200;
|
|
754
|
+
int24 baseTick2 = 1505;
|
|
755
|
+
uint160 sqrtPrice2 = TickMath.getSqrtPriceAtTick(baseTick2);
|
|
756
|
+
(Orders memory orders2, , ) = SwapLimitOrders.computeOrders(key200, true, totalSize, baseTick2, sqrtPrice2, params);
|
|
757
|
+
assertEq(orders2.ticks[0] % 200, 0, "case 2: tick must be aligned to spacing 200");
|
|
758
|
+
|
|
759
|
+
// Test case 3: negative misaligned baseTick=-95, tickSpacing=10
|
|
760
|
+
int24 baseTick3 = -95;
|
|
761
|
+
uint160 sqrtPrice3 = TickMath.getSqrtPriceAtTick(baseTick3);
|
|
762
|
+
(Orders memory orders3, , ) = SwapLimitOrders.computeOrders(key10, true, totalSize, baseTick3, sqrtPrice3, params);
|
|
763
|
+
assertEq(orders3.ticks[0] % 10, 0, "case 3: tick must be aligned to spacing 10");
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/// @notice Tests computeOrders with already-aligned baseTicks remain aligned
|
|
767
|
+
/// @dev Verifies that the fix doesn't break the common case where baseTick is already aligned
|
|
768
|
+
function test_computeOrders_alignedBaseTick_remainsAligned() public {
|
|
769
|
+
LimitOrderConfig memory params;
|
|
770
|
+
params.multiples = new uint256[](1);
|
|
771
|
+
params.percentages = new uint256[](1);
|
|
772
|
+
params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 50); // 1.02x
|
|
773
|
+
params.percentages[0] = 10000;
|
|
774
|
+
|
|
775
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
776
|
+
|
|
777
|
+
// Test case 1: baseTick=200 (aligned), tickSpacing=10
|
|
778
|
+
PoolKey memory key10 = testKey;
|
|
779
|
+
key10.tickSpacing = 10;
|
|
780
|
+
int24 baseTick1 = 200; // Already divisible by 10
|
|
781
|
+
uint160 sqrtPrice1 = TickMath.getSqrtPriceAtTick(baseTick1);
|
|
782
|
+
(Orders memory orders1, , ) = SwapLimitOrders.computeOrders(key10, true, totalSize, baseTick1, sqrtPrice1, params);
|
|
783
|
+
assertEq(orders1.ticks[0] % 10, 0, "aligned case 1: tick must be aligned to spacing 10");
|
|
784
|
+
assertGe(orders1.ticks[0], baseTick1 + 10, "aligned case 1: tick should be >= baseTick + spacing");
|
|
785
|
+
|
|
786
|
+
// Test case 2: baseTick=1400 (aligned), tickSpacing=200
|
|
787
|
+
PoolKey memory key200 = testKey;
|
|
788
|
+
key200.tickSpacing = 200;
|
|
789
|
+
int24 baseTick2 = 1400; // Already divisible by 200
|
|
790
|
+
uint160 sqrtPrice2 = TickMath.getSqrtPriceAtTick(baseTick2);
|
|
791
|
+
(Orders memory orders2, , ) = SwapLimitOrders.computeOrders(key200, true, totalSize, baseTick2, sqrtPrice2, params);
|
|
792
|
+
assertEq(orders2.ticks[0] % 200, 0, "aligned case 2: tick must be aligned to spacing 200");
|
|
793
|
+
assertGe(orders2.ticks[0], baseTick2 + 200, "aligned case 2: tick should be >= baseTick + spacing");
|
|
794
|
+
|
|
795
|
+
// Test case 3: baseTick=0 (aligned), tickSpacing=10
|
|
796
|
+
int24 baseTick3 = 0; // Already divisible by any spacing
|
|
797
|
+
uint160 sqrtPrice3 = TickMath.getSqrtPriceAtTick(baseTick3);
|
|
798
|
+
(Orders memory orders3, , ) = SwapLimitOrders.computeOrders(key10, true, totalSize, baseTick3, sqrtPrice3, params);
|
|
799
|
+
assertEq(orders3.ticks[0] % 10, 0, "aligned case 3: tick must be aligned to spacing 10");
|
|
800
|
+
assertGe(orders3.ticks[0], baseTick3 + 10, "aligned case 3: tick should be >= baseTick + spacing");
|
|
801
|
+
|
|
802
|
+
// Test case 4: negative aligned baseTick=-100, tickSpacing=10
|
|
803
|
+
int24 baseTick4 = -100; // Already divisible by 10
|
|
804
|
+
uint160 sqrtPrice4 = TickMath.getSqrtPriceAtTick(baseTick4);
|
|
805
|
+
(Orders memory orders4, , ) = SwapLimitOrders.computeOrders(key10, true, totalSize, baseTick4, sqrtPrice4, params);
|
|
806
|
+
assertEq(orders4.ticks[0] % 10, 0, "aligned case 4: tick must be aligned to spacing 10");
|
|
807
|
+
assertGe(orders4.ticks[0], baseTick4 + 10, "aligned case 4: tick should be >= baseTick + spacing");
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/// @notice Tests fix for MKT-35: skip orders when baseTick at maxTick
|
|
811
|
+
/// @dev Uses baseTick at maxTick to simulate swap exhausting liquidity
|
|
812
|
+
function test_computeOrders_baseTickAtMaxTick_skipsOrders() public {
|
|
813
|
+
LimitOrderConfig memory params;
|
|
814
|
+
params.multiples = new uint256[](1);
|
|
815
|
+
params.percentages = new uint256[](1);
|
|
816
|
+
params.multiples[0] = 2 * MULTIPLE_SCALE;
|
|
817
|
+
params.percentages[0] = 10000;
|
|
818
|
+
|
|
819
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
820
|
+
int24 maxTick = TickMath.maxUsableTick(TICK_SPACING);
|
|
821
|
+
int24 baseTick = maxTick;
|
|
822
|
+
// Use MAX_SQRT_PRICE directly since we can't compute sqrt price at maxTick
|
|
823
|
+
uint160 sqrtPriceX96 = TickMath.MAX_SQRT_PRICE - 1;
|
|
824
|
+
|
|
825
|
+
// For currency0 (buy orders), should skip and return all as unallocated
|
|
826
|
+
(Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
|
|
827
|
+
testKey,
|
|
828
|
+
true,
|
|
829
|
+
totalSize,
|
|
830
|
+
baseTick,
|
|
831
|
+
sqrtPriceX96,
|
|
832
|
+
params
|
|
833
|
+
);
|
|
834
|
+
|
|
835
|
+
assertEq(orders.sizes.length, 0, "should create no orders");
|
|
836
|
+
assertEq(allocated, 0, "should not allocate any funds");
|
|
837
|
+
assertEq(unallocated, totalSize, "all funds should be unallocated");
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/// @notice Tests fix for MKT-35: skip orders when baseTick at minTick
|
|
841
|
+
/// @dev Uses baseTick at minTick to simulate swap exhausting liquidity
|
|
842
|
+
function test_computeOrders_baseTickAtMinTick_skipsOrders() public {
|
|
843
|
+
LimitOrderConfig memory params;
|
|
844
|
+
params.multiples = new uint256[](1);
|
|
845
|
+
params.percentages = new uint256[](1);
|
|
846
|
+
params.multiples[0] = 2 * MULTIPLE_SCALE;
|
|
847
|
+
params.percentages[0] = 10000;
|
|
848
|
+
|
|
849
|
+
uint128 totalSize = uint128(100 * TEST_ORDER_SIZE);
|
|
850
|
+
int24 maxTick = TickMath.maxUsableTick(TICK_SPACING);
|
|
851
|
+
int24 minTick = -maxTick;
|
|
852
|
+
int24 baseTick = minTick;
|
|
853
|
+
// Use MIN_SQRT_PRICE directly since we can't compute sqrt price at minTick
|
|
854
|
+
uint160 sqrtPriceX96 = TickMath.MIN_SQRT_PRICE + 1;
|
|
855
|
+
|
|
856
|
+
// For currency1 (sell orders), should skip and return all as unallocated
|
|
857
|
+
(Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
|
|
858
|
+
testKey,
|
|
859
|
+
false,
|
|
860
|
+
totalSize,
|
|
861
|
+
baseTick,
|
|
862
|
+
sqrtPriceX96,
|
|
863
|
+
params
|
|
864
|
+
);
|
|
865
|
+
|
|
866
|
+
assertEq(orders.sizes.length, 0, "should create no orders");
|
|
867
|
+
assertEq(allocated, 0, "should not allocate any funds");
|
|
868
|
+
assertEq(unallocated, totalSize, "all funds should be unallocated");
|
|
869
|
+
}
|
|
672
870
|
}
|