@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.
Files changed (208) hide show
  1. package/.turbo/turbo-build$colon$js.log +85 -0
  2. package/AUDIT_NOTES.md +33 -0
  3. package/AUDIT_RFP.md +408 -0
  4. package/CHANGELOG.md +25 -0
  5. package/GAS_COMPARISON_RESULTS.md +194 -0
  6. package/LICENSE +21 -0
  7. package/README.md +650 -0
  8. package/SPEC.md +291 -0
  9. package/abis/BalanceDeltaLibrary.json +15 -0
  10. package/abis/BeforeSwapDeltaLibrary.json +15 -0
  11. package/abis/CurrencyLibrary.json +25 -0
  12. package/abis/CustomRevert.json +28 -0
  13. package/abis/IAllowanceTransfer.json +486 -0
  14. package/abis/IAuthority.json +31 -0
  15. package/abis/ICoin.json +1074 -0
  16. package/abis/IDeployedCoinVersionLookup.json +21 -0
  17. package/abis/IDopplerErrors.json +44 -0
  18. package/abis/IEIP712.json +15 -0
  19. package/abis/IERC1363.json +373 -0
  20. package/abis/IERC165.json +21 -0
  21. package/abis/IERC20.json +185 -0
  22. package/abis/IERC20Minimal.json +172 -0
  23. package/abis/IERC6909Claims.json +288 -0
  24. package/abis/IERC7572.json +21 -0
  25. package/abis/IExtsload.json +64 -0
  26. package/abis/IExttload.json +40 -0
  27. package/abis/IHasCoinType.json +15 -0
  28. package/abis/IHasPoolKey.json +42 -0
  29. package/abis/IHasRewardsRecipients.json +54 -0
  30. package/abis/IHasSwapPath.json +60 -0
  31. package/abis/IHasTotalSupplyForPositions.json +15 -0
  32. package/abis/IHooks.json +789 -0
  33. package/abis/IMsgSender.json +15 -0
  34. package/abis/IPoolManager.json +1286 -0
  35. package/abis/IProtocolFees.json +174 -0
  36. package/abis/ISupportsLimitOrderFill.json +15 -0
  37. package/abis/ISwapPathRouter.json +92 -0
  38. package/abis/ISwapRouter.json +219 -0
  39. package/abis/IUniswapV3SwapCallback.json +25 -0
  40. package/abis/IUpgradeableDestinationV4Hook.json +84 -0
  41. package/abis/IUpgradeableDestinationV4HookWithUpdateableFee.json +95 -0
  42. package/abis/IUpgradeableV4Hook.json +112 -0
  43. package/abis/IZoraHookRegistry.json +188 -0
  44. package/abis/IZoraLimitOrderBook.json +623 -0
  45. package/abis/IZoraLimitOrderBookCoinsInterface.json +67 -0
  46. package/abis/IZoraV4CoinHook.json +610 -0
  47. package/abis/Permit2Payments.json +7 -0
  48. package/abis/Position.json +7 -0
  49. package/abis/SafeCast.json +7 -0
  50. package/abis/SafeCast160.json +7 -0
  51. package/abis/SafeERC20.json +34 -0
  52. package/abis/SimpleAccessManaged.json +57 -0
  53. package/abis/SimpleAccessManager.json +351 -0
  54. package/abis/SqrtPriceMath.json +22 -0
  55. package/abis/StateLibrary.json +80 -0
  56. package/abis/SwapLimitOrders.json +22 -0
  57. package/abis/SwapWithLimitOrders.json +457 -0
  58. package/abis/TickBitmap.json +18 -0
  59. package/abis/TickMath.json +24 -0
  60. package/abis/V3ToV4SwapLib.json +28 -0
  61. package/abis/ZoraLimitOrderBook.json +771 -0
  62. package/cache/solidity-files-cache.json +1 -0
  63. package/dist/index.cjs +760 -0
  64. package/dist/index.cjs.map +1 -0
  65. package/dist/index.d.ts +2 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +731 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/wagmiGenerated.d.ts +1012 -0
  70. package/dist/wagmiGenerated.d.ts.map +1 -0
  71. package/foundry.toml +29 -0
  72. package/gas_comparison.py +49 -0
  73. package/out/BalanceDelta.sol/BalanceDeltaLibrary.json +1 -0
  74. package/out/BeforeSwapDelta.sol/BeforeSwapDeltaLibrary.json +1 -0
  75. package/out/BitMath.sol/BitMath.json +1 -0
  76. package/out/BytesLib.sol/BytesLib.json +1 -0
  77. package/out/CoinCommon.sol/CoinCommon.json +1 -0
  78. package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -0
  79. package/out/CoinConstants.sol/CoinConstants.json +1 -0
  80. package/out/Context.sol/Context.json +1 -0
  81. package/out/Currency.sol/CurrencyLibrary.json +1 -0
  82. package/out/CurrencyReserves.sol/CurrencyReserves.json +1 -0
  83. package/out/CustomRevert.sol/CustomRevert.json +1 -0
  84. package/out/DopplerMath.sol/DopplerMath.json +1 -0
  85. package/out/FixedPoint128.sol/FixedPoint128.json +1 -0
  86. package/out/FixedPoint96.sol/FixedPoint96.json +1 -0
  87. package/out/FullMath.sol/FullMath.json +1 -0
  88. package/out/IAllowanceTransfer.sol/IAllowanceTransfer.json +1 -0
  89. package/out/IAuthority.sol/IAuthority.json +1 -0
  90. package/out/ICoin.sol/ICoin.json +1 -0
  91. package/out/ICoin.sol/IHasCoinType.json +1 -0
  92. package/out/ICoin.sol/IHasPoolKey.json +1 -0
  93. package/out/ICoin.sol/IHasSwapPath.json +1 -0
  94. package/out/ICoin.sol/IHasTotalSupplyForPositions.json +1 -0
  95. package/out/IDeployedCoinVersionLookup.sol/IDeployedCoinVersionLookup.json +1 -0
  96. package/out/IDopplerErrors.sol/IDopplerErrors.json +1 -0
  97. package/out/IEIP712.sol/IEIP712.json +1 -0
  98. package/out/IERC1363.sol/IERC1363.json +1 -0
  99. package/out/IERC165.sol/IERC165.json +1 -0
  100. package/out/IERC20.sol/IERC20.json +1 -0
  101. package/out/IERC20Minimal.sol/IERC20Minimal.json +1 -0
  102. package/out/IERC6909Claims.sol/IERC6909Claims.json +1 -0
  103. package/out/IERC7572.sol/IERC7572.json +1 -0
  104. package/out/IExtsload.sol/IExtsload.json +1 -0
  105. package/out/IExttload.sol/IExttload.json +1 -0
  106. package/out/IHasRewardsRecipients.sol/IHasRewardsRecipients.json +1 -0
  107. package/out/IHooks.sol/IHooks.json +1 -0
  108. package/out/IMsgSender.sol/IMsgSender.json +1 -0
  109. package/out/IPoolManager.sol/IPoolManager.json +1 -0
  110. package/out/IProtocolFees.sol/IProtocolFees.json +1 -0
  111. package/out/ISupportsLimitOrderFill.sol/ISupportsLimitOrderFill.json +1 -0
  112. package/out/ISwapPathRouter.sol/ISwapPathRouter.json +1 -0
  113. package/out/ISwapRouter.sol/ISwapRouter.json +1 -0
  114. package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -0
  115. package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4Hook.json +1 -0
  116. package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4HookWithUpdateableFee.json +1 -0
  117. package/out/IUpgradeableV4Hook.sol/IUpgradeableV4Hook.json +1 -0
  118. package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -0
  119. package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -0
  120. package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -0
  121. package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -0
  122. package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -0
  123. package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -0
  124. package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -0
  125. package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -0
  126. package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -0
  127. package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -0
  128. package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -0
  129. package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -0
  130. package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -0
  131. package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -0
  132. package/out/LiquidityMath.sol/LiquidityMath.json +1 -0
  133. package/out/Lock.sol/Lock.json +1 -0
  134. package/out/NonzeroDeltaCount.sol/NonzeroDeltaCount.json +1 -0
  135. package/out/Path.sol/Path.json +1 -0
  136. package/out/PathKey.sol/PathKeyLibrary.json +1 -0
  137. package/out/Permit2Payments.sol/Permit2Payments.json +1 -0
  138. package/out/PoolId.sol/PoolIdLibrary.json +1 -0
  139. package/out/Position.sol/Position.json +1 -0
  140. package/out/SafeCast.sol/SafeCast.json +1 -0
  141. package/out/SafeCast160.sol/SafeCast160.json +1 -0
  142. package/out/SafeERC20.sol/SafeERC20.json +1 -0
  143. package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +1 -0
  144. package/out/SimpleAccessManager.sol/SimpleAccessManager.json +1 -0
  145. package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -0
  146. package/out/StateLibrary.sol/StateLibrary.json +1 -0
  147. package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -0
  148. package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -0
  149. package/out/TickBitmap.sol/TickBitmap.json +1 -0
  150. package/out/TickMath.sol/TickMath.json +1 -0
  151. package/out/TransientSlot.sol/TransientSlot.json +1 -0
  152. package/out/TransientStateLibrary.sol/TransientStateLibrary.json +1 -0
  153. package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -0
  154. package/out/UnsafeMath.sol/UnsafeMath.json +1 -0
  155. package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -0
  156. package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -0
  157. package/out/build-info/69718f10d1dc37f0.json +1 -0
  158. package/out/uniswap/BitMath.sol/BitMath.json +1 -0
  159. package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -0
  160. package/out/uniswap/FullMath.sol/FullMath.json +1 -0
  161. package/out/uniswap/SafeCast.sol/SafeCast.json +1 -0
  162. package/out/uniswap/TickMath.sol/TickMath.json +1 -0
  163. package/package/index.ts +1 -0
  164. package/package/wagmiGenerated.ts +738 -0
  165. package/package.json +57 -0
  166. package/remappings.txt +11 -0
  167. package/src/IZoraLimitOrderBook.sol +195 -0
  168. package/src/ZoraLimitOrderBook.sol +220 -0
  169. package/src/access/SimpleAccessManaged.sol +76 -0
  170. package/src/access/SimpleAccessManager.sol +268 -0
  171. package/src/libs/LimitOrderBitmap.sol +84 -0
  172. package/src/libs/LimitOrderCommon.sol +91 -0
  173. package/src/libs/LimitOrderCreate.sol +277 -0
  174. package/src/libs/LimitOrderFill.sol +362 -0
  175. package/src/libs/LimitOrderLiquidity.sol +222 -0
  176. package/src/libs/LimitOrderQueues.sol +101 -0
  177. package/src/libs/LimitOrderStorage.sol +34 -0
  178. package/src/libs/LimitOrderTypes.sol +41 -0
  179. package/src/libs/LimitOrderWithdraw.sol +100 -0
  180. package/src/libs/Permit2Payments.sol +41 -0
  181. package/src/libs/SwapLimitOrders.sol +209 -0
  182. package/src/router/SwapWithLimitOrders.sol +454 -0
  183. package/test/LimitOrderAccessControl.t.sol +461 -0
  184. package/test/LimitOrderBitmap.t.sol +194 -0
  185. package/test/LimitOrderCreate.t.sol +348 -0
  186. package/test/LimitOrderFill.t.sol +1005 -0
  187. package/test/LimitOrderLibraries.t.sol +354 -0
  188. package/test/LimitOrderLiquidityPayouts.t.sol +333 -0
  189. package/test/LimitOrderV4Pools.t.sol +157 -0
  190. package/test/LimitOrderWithdraw.t.sol +653 -0
  191. package/test/SimpleAccessManager.t.sol +420 -0
  192. package/test/SwapWithLimitOrders.t.sol +107 -0
  193. package/test/SwapWithLimitOrdersRouter.t.sol +1073 -0
  194. package/test/gas/LimitOrderFillGas.t.sol +1008 -0
  195. package/test/gas/LimitOrderSwapGas.t.sol +403 -0
  196. package/test/gas/logs/gas_benchmarks_fill_20251201.log +30 -0
  197. package/test/gas/logs/gas_benchmarks_swap_20251201.log +27 -0
  198. package/test/unit/LimitOrderBitmapUnit.t.sol +276 -0
  199. package/test/unit/LimitOrderCreateUnit.t.sol +358 -0
  200. package/test/unit/SwapLimitOrdersUnit.t.sol +672 -0
  201. package/test/unit/SwapLimitOrdersValidation.t.sol +423 -0
  202. package/test/unit/SwapWithLimitOrdersUnit.t.sol +321 -0
  203. package/test/utils/BaseTest.sol +793 -0
  204. package/test/utils/TestableZoraLimitOrderBook.sol +54 -0
  205. package/tsconfig.build.json +10 -0
  206. package/tsconfig.json +9 -0
  207. package/tsup.config.ts +11 -0
  208. package/wagmi.config.ts +18 -0
@@ -0,0 +1,672 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import {Test} from "forge-std/Test.sol";
5
+ import {SwapLimitOrders, LimitOrderConfig, Orders} from "../../src/libs/SwapLimitOrders.sol";
6
+ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
7
+ import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
8
+ import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
9
+ import {TickMath} from "@zoralabs/coins/src/utils/uniswap/TickMath.sol";
10
+
11
+ /// @notice Helper contract to wrap library calls for proper revert testing
12
+ contract SwapLimitOrdersWrapper {
13
+ function validate(LimitOrderConfig memory params) external pure returns (uint256) {
14
+ return SwapLimitOrders.validate(params);
15
+ }
16
+
17
+ function computeOrders(
18
+ PoolKey memory key,
19
+ bool isCurrency0,
20
+ uint128 totalSize,
21
+ int24 baseTick,
22
+ uint160 sqrtPriceX96,
23
+ LimitOrderConfig memory params
24
+ ) external pure returns (Orders memory o, uint128 allocated, uint128 unallocated) {
25
+ return SwapLimitOrders.computeOrders(key, isCurrency0, totalSize, baseTick, sqrtPriceX96, params);
26
+ }
27
+
28
+ /// @notice Test helper for isLimitOrder logic (not used in production)
29
+ function isLimitOrder(bool isCoinBuy, address swapper, int128 coinDelta, LimitOrderConfig memory params) external pure returns (bool) {
30
+ // Short-circuit early: must be a coin buy with a valid swapper and config
31
+ if (!isCoinBuy || swapper == address(0) || params.multiples.length == 0) {
32
+ return false;
33
+ }
34
+
35
+ // Must be positive and above minimum threshold
36
+ return coinDelta > 0 && uint128(coinDelta) >= SwapLimitOrders.MIN_LIMIT_ORDER_SIZE;
37
+ }
38
+ }
39
+
40
+ /// @notice Direct unit tests for SwapLimitOrders library functions
41
+ contract SwapLimitOrdersUnitTest is Test {
42
+ using SwapLimitOrders for LimitOrderConfig;
43
+
44
+ int24 constant TICK_SPACING = 200;
45
+ uint256 constant MULTIPLE_SCALE = 1e18;
46
+ uint256 constant PERCENT_SCALE = 10_000;
47
+ uint256 constant MIN_LIMIT_ORDER_SIZE = 1e18;
48
+
49
+ PoolKey internal testKey;
50
+ SwapLimitOrdersWrapper internal wrapper;
51
+
52
+ function setUp() public {
53
+ // Create a minimal valid pool key for testing
54
+ testKey = PoolKey({
55
+ currency0: Currency.wrap(address(0x1000)),
56
+ currency1: Currency.wrap(address(0x2000)),
57
+ fee: 3000,
58
+ tickSpacing: TICK_SPACING,
59
+ hooks: IHooks(address(0))
60
+ });
61
+
62
+ wrapper = new SwapLimitOrdersWrapper();
63
+ }
64
+
65
+ /// @notice Tests validate with mismatched array lengths
66
+ function test_validate_lengthMismatch_differentLengths() public {
67
+ LimitOrderConfig memory params;
68
+ params.multiples = new uint256[](3);
69
+ params.percentages = new uint256[](2); // mismatch
70
+
71
+ vm.expectRevert();
72
+ wrapper.validate(params);
73
+ }
74
+
75
+ /// @notice Tests validate with empty arrays (length == 0)
76
+ function test_validate_lengthMismatch_emptyArrays() public {
77
+ LimitOrderConfig memory params;
78
+ params.multiples = new uint256[](0);
79
+ params.percentages = new uint256[](0);
80
+
81
+ vm.expectRevert();
82
+ wrapper.validate(params);
83
+ }
84
+
85
+ /// @notice Tests validate with zero percentage
86
+ function test_validate_invalidPercent_zeroPercent() public {
87
+ LimitOrderConfig memory params;
88
+ params.multiples = new uint256[](2);
89
+ params.percentages = new uint256[](2);
90
+
91
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
92
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
93
+ params.percentages[0] = 5000; // 50%
94
+ params.percentages[1] = 0; // Zero percent - should revert
95
+
96
+ vm.expectRevert();
97
+ wrapper.validate(params);
98
+ }
99
+
100
+ /// @notice Tests validate with percentages exceeding 100%
101
+ function test_validate_percentOverflow_exceedsMax() public {
102
+ LimitOrderConfig memory params;
103
+ params.multiples = new uint256[](2);
104
+ params.percentages = new uint256[](2);
105
+
106
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
107
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
108
+ params.percentages[0] = 6000; // 60%
109
+ params.percentages[1] = 5000; // 50% (total 110% > 100%)
110
+
111
+ vm.expectRevert();
112
+ wrapper.validate(params);
113
+ }
114
+
115
+ /// @notice Tests validate with multiple at 1x (not strictly above)
116
+ function test_validate_invalidMultiple_equalToOne() public {
117
+ LimitOrderConfig memory params;
118
+ params.multiples = new uint256[](2);
119
+ params.percentages = new uint256[](2);
120
+
121
+ params.multiples[0] = MULTIPLE_SCALE; // 1.0x - should revert
122
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
123
+ params.percentages[0] = 5000;
124
+ params.percentages[1] = 5000;
125
+
126
+ vm.expectRevert();
127
+ wrapper.validate(params);
128
+ }
129
+
130
+ /// @notice Tests validate with multiple below 1x
131
+ function test_validate_invalidMultiple_belowOne() public {
132
+ LimitOrderConfig memory params;
133
+ params.multiples = new uint256[](2);
134
+ params.percentages = new uint256[](2);
135
+
136
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
137
+ params.multiples[1] = MULTIPLE_SCALE / 2; // 0.5x - should revert
138
+ params.percentages[0] = 5000;
139
+ params.percentages[1] = 5000;
140
+
141
+ vm.expectRevert();
142
+ wrapper.validate(params);
143
+ }
144
+
145
+ /// @notice Tests validate with all valid inputs (success case)
146
+ function test_validate_success_validParams() public {
147
+ LimitOrderConfig memory params;
148
+ params.multiples = new uint256[](3);
149
+ params.percentages = new uint256[](3);
150
+
151
+ params.multiples[0] = 2 * MULTIPLE_SCALE; // 2x
152
+ params.multiples[1] = 4 * MULTIPLE_SCALE; // 4x
153
+ params.multiples[2] = 8 * MULTIPLE_SCALE; // 8x
154
+ params.percentages[0] = 3000; // 30%
155
+ params.percentages[1] = 3000; // 30%
156
+ params.percentages[2] = 3000; // 30% (total 90% <= 100%)
157
+
158
+ uint256 totalPercent = wrapper.validate(params);
159
+ assertEq(totalPercent, 9000, "total percent should be 9000");
160
+ }
161
+
162
+ /// @notice Tests validate with percentages exactly at 100%
163
+ function test_validate_success_exactlyOneHundredPercent() public {
164
+ LimitOrderConfig memory params;
165
+ params.multiples = new uint256[](2);
166
+ params.percentages = new uint256[](2);
167
+
168
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
169
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
170
+ params.percentages[0] = 5000; // 50%
171
+ params.percentages[1] = 5000; // 50% (total exactly 100%)
172
+
173
+ uint256 totalPercent = wrapper.validate(params);
174
+ assertEq(totalPercent, 10000, "total percent should be 10000");
175
+ }
176
+
177
+ /// @notice Tests validate loop iterations (line 65 for loop with multiple iterations)
178
+ function test_validate_multipleIterations_checksAllElements() public {
179
+ LimitOrderConfig memory params;
180
+ params.multiples = new uint256[](5); // 5 elements to iterate
181
+ params.percentages = new uint256[](5);
182
+
183
+ for (uint256 i = 0; i < 5; i++) {
184
+ params.multiples[i] = (2 + i) * MULTIPLE_SCALE; // 2x, 3x, 4x, 5x, 6x
185
+ params.percentages[i] = 1000; // 10% each
186
+ }
187
+
188
+ uint256 totalPercent = wrapper.validate(params);
189
+ assertEq(totalPercent, 5000, "total percent should be 5000");
190
+ }
191
+
192
+ /// @notice Tests validate with single element (loop executes once)
193
+ function test_validate_singleElement_loopExecutesOnce() public {
194
+ LimitOrderConfig memory params;
195
+ params.multiples = new uint256[](1);
196
+ params.percentages = new uint256[](1);
197
+
198
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
199
+ params.percentages[0] = 10000;
200
+
201
+ uint256 totalPercent = wrapper.validate(params);
202
+ assertEq(totalPercent, 10000, "total percent should be 10000");
203
+ }
204
+
205
+ /// @notice Tests computeOrders with totalSize below MIN_LIMIT_ORDER_SIZE (dust)
206
+ function test_computeOrders_belowMinSize_returnsEmpty() public {
207
+ LimitOrderConfig memory params;
208
+ params.multiples = new uint256[](2);
209
+ params.percentages = new uint256[](2);
210
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
211
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
212
+ params.percentages[0] = 5000;
213
+ params.percentages[1] = 5000;
214
+
215
+ uint128 totalSize = uint128(MIN_LIMIT_ORDER_SIZE - 1); // Below minimum
216
+ int24 baseTick = 0;
217
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
218
+
219
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
220
+ testKey,
221
+ true,
222
+ totalSize,
223
+ baseTick,
224
+ sqrtPriceX96,
225
+ params
226
+ );
227
+
228
+ // Should return empty arrays
229
+ assertEq(orders.sizes.length, 0, "sizes should be empty");
230
+ assertEq(orders.ticks.length, 0, "ticks should be empty");
231
+ assertEq(allocated, 0, "allocated should be 0");
232
+ assertEq(unallocated, totalSize, "unallocated should equal totalSize");
233
+ }
234
+
235
+ /// @notice Tests computeOrders with totalSize exactly at MIN_LIMIT_ORDER_SIZE
236
+ function test_computeOrders_exactlyMinSize_createsOrders() public {
237
+ LimitOrderConfig memory params;
238
+ params.multiples = new uint256[](2);
239
+ params.percentages = new uint256[](2);
240
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
241
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
242
+ params.percentages[0] = 5000;
243
+ params.percentages[1] = 5000;
244
+
245
+ uint128 totalSize = uint128(MIN_LIMIT_ORDER_SIZE); // Exactly at minimum
246
+ int24 baseTick = 0;
247
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
248
+
249
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
250
+ testKey,
251
+ true,
252
+ totalSize,
253
+ baseTick,
254
+ sqrtPriceX96,
255
+ params
256
+ );
257
+
258
+ // Should create orders
259
+ assertEq(orders.sizes.length, 2, "should create 2 orders");
260
+ assertEq(orders.ticks.length, 2, "should create 2 ticks");
261
+ assertGt(allocated, 0, "should allocate some amount");
262
+ }
263
+
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 MIN_LIMIT_ORDER_SIZE=1e18 and PERCENT_SCALE=10000
266
+ /// since even 1 basis point of 1e18 = 1e14. The skip logic exists for safety in edge cases.
267
+ function test_computeOrders_multipleOrders_createsAll() public {
268
+ LimitOrderConfig memory params;
269
+ params.multiples = new uint256[](2);
270
+ params.percentages = new uint256[](2);
271
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
272
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
273
+ params.percentages[0] = 5000;
274
+ params.percentages[1] = 5000;
275
+
276
+ uint128 totalSize = uint128(MIN_LIMIT_ORDER_SIZE * 10);
277
+ int24 baseTick = 0;
278
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
279
+
280
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
281
+ testKey,
282
+ true,
283
+ totalSize,
284
+ baseTick,
285
+ sqrtPriceX96,
286
+ params
287
+ );
288
+
289
+ // Both orders should be created
290
+ assertEq(orders.sizes.length, 2, "should create 2 orders");
291
+ assertEq(orders.ticks.length, 2, "should have 2 ticks");
292
+ }
293
+
294
+ /// @notice Tests computeOrders loop with many iterations (line 105 for loop)
295
+ function test_computeOrders_manyOrders_loopIteratesMultipleTimes() public {
296
+ LimitOrderConfig memory params;
297
+ params.multiples = new uint256[](6); // Many orders
298
+ params.percentages = new uint256[](6);
299
+
300
+ for (uint256 i = 0; i < 6; i++) {
301
+ params.multiples[i] = (2 + i) * MULTIPLE_SCALE; // 2x, 3x, 4x, 5x, 6x, 7x
302
+ params.percentages[i] = 1000; // 10% each (60% total)
303
+ }
304
+
305
+ uint128 totalSize = uint128(MIN_LIMIT_ORDER_SIZE * 100);
306
+ int24 baseTick = 0;
307
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
308
+
309
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
310
+ testKey,
311
+ true,
312
+ totalSize,
313
+ baseTick,
314
+ sqrtPriceX96,
315
+ params
316
+ );
317
+
318
+ // All 6 orders should be created
319
+ assertEq(orders.sizes.length, 6, "should create 6 orders");
320
+ assertEq(orders.ticks.length, 6, "should have 6 ticks");
321
+ }
322
+
323
+ /// @notice Tests computeOrders with single order (loop executes once)
324
+ function test_computeOrders_singleOrder_loopExecutesOnce() public {
325
+ LimitOrderConfig memory params;
326
+ params.multiples = new uint256[](1);
327
+ params.percentages = new uint256[](1);
328
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
329
+ params.percentages[0] = 10000;
330
+
331
+ uint128 totalSize = uint128(MIN_LIMIT_ORDER_SIZE * 10);
332
+ int24 baseTick = 0;
333
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
334
+
335
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
336
+ testKey,
337
+ true,
338
+ totalSize,
339
+ baseTick,
340
+ sqrtPriceX96,
341
+ params
342
+ );
343
+
344
+ assertEq(orders.sizes.length, 1, "should create 1 order");
345
+ assertEq(orders.ticks.length, 1, "should have 1 tick");
346
+ }
347
+
348
+ /// @notice Tests computeOrders with large totalSize and valid percentages
349
+ function test_computeOrders_largeSize_allocatesCorrectly() public {
350
+ LimitOrderConfig memory params;
351
+ params.multiples = new uint256[](2);
352
+ params.percentages = new uint256[](2);
353
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
354
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
355
+ params.percentages[0] = 6000; // 60%
356
+ params.percentages[1] = 3000; // 30% (total 90%)
357
+
358
+ uint128 totalSize = uint128(1000 * MIN_LIMIT_ORDER_SIZE);
359
+ int24 baseTick = 0;
360
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
361
+
362
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
363
+ testKey,
364
+ true,
365
+ totalSize,
366
+ baseTick,
367
+ sqrtPriceX96,
368
+ params
369
+ );
370
+
371
+ assertEq(orders.sizes.length, 2, "should create 2 orders");
372
+
373
+ // Verify order sizes apply percentages sequentially (second rung sized off remaining 40%)
374
+ uint256 expectedFirst = (totalSize * 6000) / PERCENT_SCALE; // 60% of total
375
+ uint256 expectedSecond = ((totalSize - expectedFirst) * 3000) / PERCENT_SCALE; // 30% of remaining
376
+ assertEq(orders.sizes[0], expectedFirst, "first order size should be 60% of total");
377
+ assertEq(orders.sizes[1], expectedSecond, "second order size should be 30% of remaining");
378
+
379
+ // Verify allocated + unallocated = totalSize
380
+ assertEq(uint256(allocated) + uint256(unallocated), totalSize, "allocated + unallocated should equal totalSize");
381
+ }
382
+
383
+ /// @notice Tests computeOrders sizes each rung off the remaining balance (geometric sizing)
384
+ function test_computeOrders_percentages_applyToRemaining() public view {
385
+ LimitOrderConfig memory params;
386
+ params.multiples = new uint256[](3);
387
+ params.percentages = new uint256[](3);
388
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
389
+ params.multiples[1] = 3 * MULTIPLE_SCALE;
390
+ params.multiples[2] = 4 * MULTIPLE_SCALE;
391
+ params.percentages[0] = 2000; // 20%
392
+ params.percentages[1] = 2000; // 20% of remaining
393
+ params.percentages[2] = 2000; // 20% of remaining
394
+
395
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE); // 100 units for easy math
396
+ int24 baseTick = 0;
397
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
398
+
399
+ (Orders memory orders, uint128 allocated, uint128 unallocated) = SwapLimitOrders.computeOrders(
400
+ testKey,
401
+ true,
402
+ totalSize,
403
+ baseTick,
404
+ sqrtPriceX96,
405
+ params
406
+ );
407
+
408
+ assertEq(orders.sizes.length, 3, "should create 3 orders");
409
+
410
+ uint256 expectedFirst = (totalSize * 2000) / PERCENT_SCALE; // 20 of 100
411
+ uint256 remainingAfterFirst = totalSize - expectedFirst; // 80
412
+ uint256 expectedSecond = (remainingAfterFirst * 2000) / PERCENT_SCALE; // 16
413
+ uint256 remainingAfterSecond = remainingAfterFirst - expectedSecond; // 64
414
+ uint256 expectedThird = (remainingAfterSecond * 2000) / PERCENT_SCALE; // 12
415
+
416
+ assertEq(orders.sizes[0], expectedFirst, "first order size mismatch");
417
+ assertEq(orders.sizes[1], expectedSecond, "second order size mismatch");
418
+ assertEq(orders.sizes[2], expectedThird, "third order size mismatch");
419
+
420
+ // Conservation: allocated + unallocated == totalSize
421
+ assertEq(uint256(allocated) + uint256(unallocated), totalSize, "conservation must hold");
422
+ assertEq(unallocated, uint128(totalSize - expectedFirst - expectedSecond - expectedThird), "unallocated should be remainder");
423
+ }
424
+
425
+ /// @notice Tests computeOrders with extreme multiples (tick clamping)
426
+ function test_computeOrders_extremeMultiples_clampsToMaxTick() public {
427
+ LimitOrderConfig memory params;
428
+ params.multiples = new uint256[](1);
429
+ params.percentages = new uint256[](1);
430
+ params.multiples[0] = 1000 * MULTIPLE_SCALE; // 1000x - extremely high
431
+ params.percentages[0] = 10000; // 100%
432
+
433
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
434
+ int24 baseTick = 0;
435
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
436
+
437
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, true, totalSize, baseTick, sqrtPriceX96, params);
438
+
439
+ int24 maxTick = TickMath.maxUsableTick(TICK_SPACING);
440
+
441
+ // Tick should be clamped to max usable tick
442
+ assertLe(orders.ticks[0], maxTick, "tick should be clamped to max");
443
+ assertGt(orders.ticks[0], baseTick, "tick should be above base tick");
444
+ }
445
+
446
+ /// @notice Tests computeOrders for currency1 (isCurrency0 = false) - tests line 147 branch
447
+ function test_computeOrders_currency1_ticksBelowBase() public {
448
+ LimitOrderConfig memory params;
449
+ params.multiples = new uint256[](2);
450
+ params.percentages = new uint256[](2);
451
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
452
+ params.multiples[1] = 4 * MULTIPLE_SCALE;
453
+ params.percentages[0] = 5000;
454
+ params.percentages[1] = 5000;
455
+
456
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
457
+ int24 baseTick = 10000;
458
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
459
+
460
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, false, totalSize, baseTick, sqrtPriceX96, params);
461
+
462
+ // For currency1 (isCurrency0 = false), ticks should be below baseTick
463
+ assertLt(orders.ticks[0], baseTick, "tick 0 should be below base tick");
464
+ assertLt(orders.ticks[1], baseTick, "tick 1 should be below base tick");
465
+ assertLt(orders.ticks[1], orders.ticks[0], "higher multiple should have lower tick");
466
+ }
467
+
468
+ /// @notice Tests computeOrders with sqrt price overflow (line 155 branch: scaled > type(uint160).max)
469
+ function test_computeOrders_sqrtPriceOverflow_clampsToMax() public {
470
+ LimitOrderConfig memory params;
471
+ params.multiples = new uint256[](1);
472
+ params.percentages = new uint256[](1);
473
+ // Use extremely large multiple to trigger overflow
474
+ params.multiples[0] = 1000000 * MULTIPLE_SCALE; // 1,000,000x
475
+ params.percentages[0] = 10000;
476
+
477
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
478
+ // Use moderate base tick (TickMath has max/min around ±887272)
479
+ int24 baseTick = 100000; // Moderate positive tick
480
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
481
+
482
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, true, totalSize, baseTick, sqrtPriceX96, params);
483
+
484
+ // Should successfully create order with clamped tick
485
+ assertEq(orders.sizes.length, 1, "should create 1 order");
486
+ assertLe(orders.ticks[0], TickMath.maxUsableTick(TICK_SPACING), "tick should be <= max");
487
+ }
488
+
489
+ /// @notice Tests computeOrders near minimum tick boundary (line 169 branch: aligned < minTick)
490
+ function test_computeOrders_nearMinTick_clampsToMin() public {
491
+ LimitOrderConfig memory params;
492
+ params.multiples = new uint256[](1);
493
+ params.percentages = new uint256[](1);
494
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
495
+ params.percentages[0] = 10000;
496
+
497
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
498
+ // Use moderate negative base tick for currency1
499
+ int24 baseTick = -100000; // Moderate negative tick
500
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
501
+
502
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, false, totalSize, baseTick, sqrtPriceX96, params);
503
+
504
+ // Should successfully create order with clamped tick
505
+ assertEq(orders.sizes.length, 1, "should create 1 order");
506
+ assertGe(orders.ticks[0], TickMath.minUsableTick(TICK_SPACING), "tick should be >= min");
507
+ }
508
+
509
+ /// @notice Tests computeOrders with tick too close to base (line 170: isCurrency0 && aligned < minAway)
510
+ function test_computeOrders_currency0_tooCloseToBase_clampsToMinAway() public {
511
+ LimitOrderConfig memory params;
512
+ params.multiples = new uint256[](1);
513
+ params.percentages = new uint256[](1);
514
+ // Use small multiple that would produce tick very close to base
515
+ params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 100); // 1.01x
516
+ params.percentages[0] = 10000;
517
+
518
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
519
+ int24 baseTick = 0;
520
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
521
+
522
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, true, totalSize, baseTick, sqrtPriceX96, params);
523
+
524
+ // For currency0, tick should be at least tickSpacing away from base
525
+ assertGe(orders.ticks[0], baseTick + TICK_SPACING, "tick should be >= baseTick + spacing");
526
+ }
527
+
528
+ /// @notice Tests computeOrders with tick too close to base (line 171: !isCurrency0 && aligned > minAway)
529
+ function test_computeOrders_currency1_tooCloseToBase_clampsToMinAway() public {
530
+ LimitOrderConfig memory params;
531
+ params.multiples = new uint256[](1);
532
+ params.percentages = new uint256[](1);
533
+ // Use small multiple that would produce tick very close to base
534
+ params.multiples[0] = MULTIPLE_SCALE + (MULTIPLE_SCALE / 100); // 1.01x
535
+ params.percentages[0] = 10000;
536
+
537
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
538
+ int24 baseTick = 0;
539
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
540
+
541
+ (Orders memory orders, , ) = SwapLimitOrders.computeOrders(testKey, false, totalSize, baseTick, sqrtPriceX96, params);
542
+
543
+ // For currency1, tick should be at least tickSpacing away from base (below it)
544
+ assertLe(orders.ticks[0], baseTick - TICK_SPACING, "tick should be <= baseTick - spacing");
545
+ }
546
+
547
+ /// @notice Tests _sqrtMultiple with zero (line 184 branch: result == 0)
548
+ /// @dev This tests the error case by using a multiple that would cause sqrt to fail
549
+ function test_computeOrders_zeroMultiple_reverts() public {
550
+ LimitOrderConfig memory params;
551
+ params.multiples = new uint256[](1);
552
+ params.percentages = new uint256[](1);
553
+ params.multiples[0] = 0; // Zero multiple - should revert in _sqrtMultiple
554
+ params.percentages[0] = 10000;
555
+
556
+ uint128 totalSize = uint128(100 * MIN_LIMIT_ORDER_SIZE);
557
+ int24 baseTick = 0;
558
+ uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(baseTick);
559
+
560
+ vm.expectRevert();
561
+ wrapper.computeOrders(testKey, true, totalSize, baseTick, sqrtPriceX96, params);
562
+ }
563
+
564
+ /// @notice Tests isLimitOrder when not a coin buy (first condition in line 48)
565
+ function test_isLimitOrder_notCoinBuy_returnsFalse() public {
566
+ LimitOrderConfig memory params;
567
+ params.multiples = new uint256[](1);
568
+ params.percentages = new uint256[](1);
569
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
570
+ params.percentages[0] = 10000;
571
+
572
+ bool isCoinBuy = false; // NOT isCoinBuy - tests first branch
573
+ address swapper = address(0x1234);
574
+ int128 coinDelta = int128(int256(MIN_LIMIT_ORDER_SIZE * 2));
575
+
576
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when not coin buy");
577
+ }
578
+
579
+ /// @notice Tests isLimitOrder when isCoinBuy is true (ensures we go past first condition)
580
+ function test_isLimitOrder_isCoinBuyTrue_checksOtherConditions() public {
581
+ LimitOrderConfig memory params;
582
+ params.multiples = new uint256[](0); // Empty - no orders
583
+ params.percentages = new uint256[](0);
584
+
585
+ bool isCoinBuy = true; // Pass first condition
586
+ address swapper = address(0x1234);
587
+ int128 coinDelta = int128(int256(MIN_LIMIT_ORDER_SIZE * 2));
588
+
589
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when no orders");
590
+ }
591
+
592
+ /// @notice Tests isLimitOrder when no orders in params
593
+ function test_isLimitOrder_noOrders_returnsFalse() public {
594
+ LimitOrderConfig memory params;
595
+ params.multiples = new uint256[](0);
596
+ params.percentages = new uint256[](0);
597
+
598
+ bool isCoinBuy = true;
599
+ address swapper = address(0x1234);
600
+ // casting to 'int256' is safe because MIN_LIMIT_ORDER_SIZE will not overflow int128
601
+ int128 coinDelta = int128(int256(MIN_LIMIT_ORDER_SIZE * 2));
602
+
603
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when no orders");
604
+ }
605
+
606
+ /// @notice Tests isLimitOrder when swapper is zero address
607
+ function test_isLimitOrder_zeroSwapper_returnsFalse() public {
608
+ LimitOrderConfig memory params;
609
+ params.multiples = new uint256[](1);
610
+ params.percentages = new uint256[](1);
611
+
612
+ bool isCoinBuy = true;
613
+ address swapper = address(0); // Zero address
614
+ int128 coinDelta = int128(int256(MIN_LIMIT_ORDER_SIZE * 2));
615
+
616
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when swapper is zero");
617
+ }
618
+
619
+ /// @notice Tests isLimitOrder when coinDelta is negative
620
+ function test_isLimitOrder_negativeCoinDelta_returnsFalse() public {
621
+ LimitOrderConfig memory params;
622
+ params.multiples = new uint256[](1);
623
+ params.percentages = new uint256[](1);
624
+
625
+ bool isCoinBuy = true;
626
+ address swapper = address(0x1234);
627
+ int128 coinDelta = -100; // Negative delta
628
+
629
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false for negative delta");
630
+ }
631
+
632
+ /// @notice Tests isLimitOrder when coinDelta is zero
633
+ function test_isLimitOrder_zeroCoinDelta_returnsFalse() public {
634
+ LimitOrderConfig memory params;
635
+ params.multiples = new uint256[](1);
636
+ params.percentages = new uint256[](1);
637
+
638
+ bool isCoinBuy = true;
639
+ address swapper = address(0x1234);
640
+ int128 coinDelta = 0; // Zero delta
641
+
642
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false for zero delta");
643
+ }
644
+
645
+ /// @notice Tests isLimitOrder when coinDelta below MIN_LIMIT_ORDER_SIZE (dust)
646
+ function test_isLimitOrder_belowMinSize_returnsFalse() public {
647
+ LimitOrderConfig memory params;
648
+ params.multiples = new uint256[](1);
649
+ params.percentages = new uint256[](1);
650
+
651
+ bool isCoinBuy = true;
652
+ address swapper = address(0x1234);
653
+ int128 coinDelta = int128(int256(MIN_LIMIT_ORDER_SIZE - 1)); // Below minimum
654
+
655
+ assertFalse(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return false when below min size");
656
+ }
657
+
658
+ /// @notice Tests isLimitOrder when all conditions are met (success case)
659
+ function test_isLimitOrder_allConditionsMet_returnsTrue() public {
660
+ LimitOrderConfig memory params;
661
+ params.multiples = new uint256[](1);
662
+ params.percentages = new uint256[](1);
663
+ params.multiples[0] = 2 * MULTIPLE_SCALE;
664
+ params.percentages[0] = 10000;
665
+
666
+ bool isCoinBuy = true;
667
+ address swapper = address(0x1234);
668
+ int128 coinDelta = int128(int256(MIN_LIMIT_ORDER_SIZE * 2));
669
+
670
+ assertTrue(wrapper.isLimitOrder(isCoinBuy, swapper, coinDelta, params), "should return true when all conditions met");
671
+ }
672
+ }