genius-intents 0.18.2 → 0.19.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 (123) hide show
  1. package/CHANGELOG.md +46 -3
  2. package/dist/genius-intents.d.ts.map +1 -1
  3. package/dist/genius-intents.js +8 -2
  4. package/dist/genius-intents.js.map +1 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/dex/algebra/algebra-factory.abi.d.ts +3 -0
  10. package/dist/lib/dex/algebra/algebra-factory.abi.d.ts.map +1 -0
  11. package/dist/lib/dex/algebra/algebra-factory.abi.js +34 -0
  12. package/dist/lib/dex/algebra/algebra-factory.abi.js.map +1 -0
  13. package/dist/lib/dex/algebra/algebra-quoter.abi.d.ts +3 -0
  14. package/dist/lib/dex/algebra/algebra-quoter.abi.d.ts.map +1 -0
  15. package/dist/lib/dex/algebra/algebra-quoter.abi.js +135 -0
  16. package/dist/lib/dex/algebra/algebra-quoter.abi.js.map +1 -0
  17. package/dist/lib/dex/algebra/algebra-router.abi.d.ts +3 -0
  18. package/dist/lib/dex/algebra/algebra-router.abi.d.ts.map +1 -0
  19. package/dist/lib/dex/algebra/algebra-router.abi.js +273 -0
  20. package/dist/lib/dex/algebra/algebra-router.abi.js.map +1 -0
  21. package/dist/lib/dex/uniswapv3/slipstream-quoter.abi.d.ts +3 -0
  22. package/dist/lib/dex/uniswapv3/slipstream-quoter.abi.d.ts.map +1 -0
  23. package/dist/lib/dex/uniswapv3/slipstream-quoter.abi.js +30 -0
  24. package/dist/lib/dex/uniswapv3/slipstream-quoter.abi.js.map +1 -0
  25. package/dist/lib/dex/uniswapv3/slipstream-router.abi.d.ts +3 -0
  26. package/dist/lib/dex/uniswapv3/slipstream-router.abi.d.ts.map +1 -0
  27. package/dist/lib/dex/uniswapv3/slipstream-router.abi.js +45 -0
  28. package/dist/lib/dex/uniswapv3/slipstream-router.abi.js.map +1 -0
  29. package/dist/lib/dex/ve33/aerodrome-factory.abi.d.ts +3 -0
  30. package/dist/lib/dex/ve33/aerodrome-factory.abi.d.ts.map +1 -0
  31. package/dist/lib/dex/ve33/aerodrome-factory.abi.js +17 -0
  32. package/dist/lib/dex/ve33/aerodrome-factory.abi.js.map +1 -0
  33. package/dist/lib/dex/ve33/aerodrome-router.abi.d.ts +3 -0
  34. package/dist/lib/dex/ve33/aerodrome-router.abi.d.ts.map +1 -0
  35. package/dist/lib/dex/ve33/aerodrome-router.abi.js +119 -0
  36. package/dist/lib/dex/ve33/aerodrome-router.abi.js.map +1 -0
  37. package/dist/lib/dex/ve33/blackhole-router.abi.d.ts +3 -0
  38. package/dist/lib/dex/ve33/blackhole-router.abi.d.ts.map +1 -0
  39. package/dist/lib/dex/ve33/blackhole-router.abi.js +1492 -0
  40. package/dist/lib/dex/ve33/blackhole-router.abi.js.map +1 -0
  41. package/dist/lib/dex/ve33/pharaoh-router.abi.d.ts +3 -0
  42. package/dist/lib/dex/ve33/pharaoh-router.abi.d.ts.map +1 -0
  43. package/dist/lib/dex/ve33/pharaoh-router.abi.js +502 -0
  44. package/dist/lib/dex/ve33/pharaoh-router.abi.js.map +1 -0
  45. package/dist/lib/dex/ve33/velodrome-router.abi.d.ts +3 -0
  46. package/dist/lib/dex/ve33/velodrome-router.abi.d.ts.map +1 -0
  47. package/dist/lib/dex/ve33/velodrome-router.abi.js +634 -0
  48. package/dist/lib/dex/ve33/velodrome-router.abi.js.map +1 -0
  49. package/dist/protocols/algebra/algebra.service.d.ts +61 -0
  50. package/dist/protocols/algebra/algebra.service.d.ts.map +1 -0
  51. package/dist/protocols/algebra/algebra.service.js +562 -0
  52. package/dist/protocols/algebra/algebra.service.js.map +1 -0
  53. package/dist/protocols/algebra/algebra.types.d.ts +83 -0
  54. package/dist/protocols/algebra/algebra.types.d.ts.map +1 -0
  55. package/dist/protocols/algebra/algebra.types.js +9 -0
  56. package/dist/protocols/algebra/algebra.types.js.map +1 -0
  57. package/dist/protocols/algebra/index.d.ts +3 -0
  58. package/dist/protocols/algebra/index.d.ts.map +1 -0
  59. package/dist/protocols/algebra/index.js +21 -0
  60. package/dist/protocols/algebra/index.js.map +1 -0
  61. package/dist/protocols/okx/okx.service.d.ts +9 -8
  62. package/dist/protocols/okx/okx.service.d.ts.map +1 -1
  63. package/dist/protocols/okx/okx.service.js +133 -143
  64. package/dist/protocols/okx/okx.service.js.map +1 -1
  65. package/dist/protocols/okx/okx.types.d.ts +9 -3
  66. package/dist/protocols/okx/okx.types.d.ts.map +1 -1
  67. package/dist/protocols/relay/relay.service.d.ts +3 -0
  68. package/dist/protocols/relay/relay.service.d.ts.map +1 -1
  69. package/dist/protocols/relay/relay.service.js +7 -1
  70. package/dist/protocols/relay/relay.service.js.map +1 -1
  71. package/dist/protocols/v2-dex/v2-dex.service.d.ts +0 -3
  72. package/dist/protocols/v2-dex/v2-dex.service.d.ts.map +1 -1
  73. package/dist/protocols/v2-dex/v2-dex.service.js +54 -55
  74. package/dist/protocols/v2-dex/v2-dex.service.js.map +1 -1
  75. package/dist/protocols/v2-dex/v2-dex.types.d.ts +0 -10
  76. package/dist/protocols/v2-dex/v2-dex.types.d.ts.map +1 -1
  77. package/dist/protocols/v3-dex/v3-dex.service.d.ts +50 -6
  78. package/dist/protocols/v3-dex/v3-dex.service.d.ts.map +1 -1
  79. package/dist/protocols/v3-dex/v3-dex.service.js +369 -193
  80. package/dist/protocols/v3-dex/v3-dex.service.js.map +1 -1
  81. package/dist/protocols/v3-dex/v3-dex.types.d.ts +4 -1
  82. package/dist/protocols/v3-dex/v3-dex.types.d.ts.map +1 -1
  83. package/dist/protocols/v3-dex/v3-dex.types.js +3 -0
  84. package/dist/protocols/v3-dex/v3-dex.types.js.map +1 -1
  85. package/dist/protocols/ve33/index.d.ts +3 -0
  86. package/dist/protocols/ve33/index.d.ts.map +1 -0
  87. package/dist/protocols/ve33/index.js +6 -0
  88. package/dist/protocols/ve33/index.js.map +1 -0
  89. package/dist/protocols/ve33/ve33.handlers.d.ts +3 -0
  90. package/dist/protocols/ve33/ve33.handlers.d.ts.map +1 -0
  91. package/dist/protocols/ve33/ve33.handlers.js +187 -0
  92. package/dist/protocols/ve33/ve33.handlers.js.map +1 -0
  93. package/dist/protocols/ve33/ve33.service.d.ts +26 -0
  94. package/dist/protocols/ve33/ve33.service.d.ts.map +1 -0
  95. package/dist/protocols/ve33/ve33.service.js +486 -0
  96. package/dist/protocols/ve33/ve33.service.js.map +1 -0
  97. package/dist/protocols/ve33/ve33.types.d.ts +136 -0
  98. package/dist/protocols/ve33/ve33.types.d.ts.map +1 -0
  99. package/dist/protocols/ve33/ve33.types.js +11 -0
  100. package/dist/protocols/ve33/ve33.types.js.map +1 -0
  101. package/dist/types/enums.d.ts +5 -2
  102. package/dist/types/enums.d.ts.map +1 -1
  103. package/dist/types/enums.js +3 -0
  104. package/dist/types/enums.js.map +1 -1
  105. package/dist/types/price-params.d.ts +4 -0
  106. package/dist/types/price-params.d.ts.map +1 -1
  107. package/dist/types/price-response.d.ts +4 -2
  108. package/dist/types/price-response.d.ts.map +1 -1
  109. package/dist/types/quote-response.d.ts +3 -1
  110. package/dist/types/quote-response.d.ts.map +1 -1
  111. package/dist/utils/dex-deployment-key.d.ts +14 -0
  112. package/dist/utils/dex-deployment-key.d.ts.map +1 -0
  113. package/dist/utils/dex-deployment-key.js +17 -0
  114. package/dist/utils/dex-deployment-key.js.map +1 -0
  115. package/dist/utils/min-amount-out.d.ts +12 -0
  116. package/dist/utils/min-amount-out.d.ts.map +1 -0
  117. package/dist/utils/min-amount-out.js +18 -0
  118. package/dist/utils/min-amount-out.js.map +1 -0
  119. package/dist/utils/sort-addresses.d.ts +2 -0
  120. package/dist/utils/sort-addresses.d.ts.map +1 -0
  121. package/dist/utils/sort-addresses.js +14 -0
  122. package/dist/utils/sort-addresses.js.map +1 -0
  123. package/package.json +1 -1
@@ -7,17 +7,22 @@ const v3_dex_types_1 = require("./v3-dex.types");
7
7
  const sushiswap_route_processor_9_abi_1 = require("../../lib/dex/sushiswap/sushiswap-route-processor-9.abi");
8
8
  const pacakeswapV3_router_abi_1 = require("../../lib/dex/pancakeswap/pacakeswapV3-router.abi");
9
9
  const v3_offchain_quoter_service_1 = require("../../lib/dex/uniswapv3/v3-offchain-quoter.service");
10
+ const slipstream_quoter_abi_1 = require("../../lib/dex/uniswapv3/slipstream-quoter.abi");
11
+ const slipstream_router_abi_1 = require("../../lib/dex/uniswapv3/slipstream-router.abi");
10
12
  const uniswapV3_quoter_abi_1 = require("../../lib/dex/uniswapv3/uniswapV3-quoter.abi");
11
13
  const uniswapV3_router_abi_1 = require("../../lib/dex/uniswapv3/uniswapV3-router.abi");
12
14
  const uniswapV3_pool_abi_1 = require("../../lib/dex/uniswapv3/uniswapV3-pool.abi");
13
15
  const enums_1 = require("../../types/enums");
16
+ const min_amount_out_1 = require("../../utils/min-amount-out");
14
17
  const wrapped_native_1 = require("../../utils/wrapped-native");
15
18
  const constants_1 = require("../../utils/constants");
16
19
  const is_native_1 = require("../../utils/is-native");
17
20
  const logger_1 = require("../../utils/logger");
18
21
  const utils_1 = require("../../utils");
22
+ const sort_addresses_1 = require("../../utils/sort-addresses");
23
+ const dex_deployment_key_1 = require("../../utils/dex-deployment-key");
19
24
  /**
20
- * Service for interacting with V3-style decentralized exchanges (DEXs) such as Uniswap V3, PancakeSwap V3, and SushiSwap V3.
25
+ * Service for interacting with V3-style decentralized exchanges (DEXs) such as Uniswap V3, PancakeSwap V3, Slipstream, and SushiSwap V3.
21
26
  *
22
27
  * This service provides price discovery and swap quote functionality for supported chains and DEX deployments.
23
28
  * It supports multicall-based quoting across multiple fee tiers and deployments, with fallback logic for different quoter contract versions.
@@ -25,13 +30,48 @@ const utils_1 = require("../../utils");
25
30
  * @remarks
26
31
  * - Only single-chain swaps are supported.
27
32
  * - Deployments and RPC clients are configured via the constructor.
28
- * - Supports Uniswap V3, PancakeSwap V3, and SushiSwap V3 deployments on Avalanche, Arbitrum, BSC, Base, Ethereum, Optimism, and Polygon.
33
+ * - Supports Uniswap V3, PancakeSwap V3, Slipstream, and SushiSwap V3 deployments on Avalanche, Arbitrum, BSC, Base, Ethereum, Optimism, HyperEVM, and Polygon.
29
34
  *
30
35
  * @example
31
36
  * ```typescript
32
- * const service = new V3StyleDexService(config);
33
- * const price = await service.fetchPrice({ ... });
34
- * const quote = await service.fetchQuote({ ... });
37
+ import { base, optimism } from 'viem/chains';
38
+
39
+ async function t() {
40
+ const rpcs = {
41
+ [ChainIdEnum.BASE]: '<url>',
42
+ [ChainIdEnum.OPTIMISM]: '<url>',
43
+ };
44
+
45
+ const solidlyChainConfigs = {
46
+ [ChainIdEnum.BASE]: base,
47
+ [ChainIdEnum.OPTIMISM]: optimism,
48
+ };
49
+
50
+ const s = new V3StyleDexService({ rpcs, uniV3ChainConfigs: solidlyChainConfigs });
51
+ const a = await s.fetchQuote({
52
+ from: '0x055698dead6666c0690B1419647556149005504D',
53
+ receiver: '0x055698dead6666c0690B1419647556149005504D',
54
+ tokenOut: ZERO_ADDRESS, // WETH
55
+ tokenIn: '0x940181a94A35A4569E4529A3CDfB74e38FD98631', // USDC
56
+ amountIn: '100000000000000000000', // s0.01 WETH
57
+ networkIn: ChainIdEnum.BASE,
58
+ networkOut: ChainIdEnum.BASE,
59
+ slippage: 10, // 1%
60
+ });
61
+
62
+ const c = await s.fetchQuote({
63
+ from: '0x055698dead6666c0690B1419647556149005504D',
64
+ receiver: '0x055698dead6666c0690B1419647556149005504D',
65
+ tokenIn: ZERO_ADDRESS, // WETH
66
+ tokenOut: '0x9560e827aF36c94D2Ac33a39bCE1Fe78631088Db', // USDC
67
+ amountIn: '100000000000000000', // 0.01 WETH
68
+ networkIn: ChainIdEnum.OPTIMISM,
69
+ networkOut: ChainIdEnum.OPTIMISM,
70
+ slippage: 10, // 1%
71
+ });
72
+ }
73
+
74
+ t();
35
75
  * ```
36
76
  *
37
77
  * @implements IIntentProtocol
@@ -74,6 +114,14 @@ class V3StyleDexService {
74
114
  this.pancakeFeeTiers = [100, 500, 2500, 10000];
75
115
  this.pangolinFeeTiers = [40, 100, 500, 2500, 8000];
76
116
  this.hyperswapFeeTiers = [100, 500, 3000, 10000];
117
+ this.pharaohFeeTiers = [50, 100, 250, 500, 3000, 10000];
118
+ this.aerodromeFeeTiers = [100, 400, 500, 3000, 10000];
119
+ this.velodromeFeeTiers = [500, 3000, 10000];
120
+ /**
121
+ * Tick spacings for slipstream style dexes
122
+ */
123
+ this.aerodromeTickSpacings = [1, 10, 60, 200];
124
+ this.velodromeTickSpacings = [10, 60, 200];
77
125
  /**
78
126
  * The deployments supported out of the box for V3 style dexes
79
127
  */
@@ -93,6 +141,13 @@ class V3StyleDexService {
93
141
  router: '0x5485A0751a249225D3bA2f6f296551507e22547f',
94
142
  initHash: '0x40231f6b438bce0797c9ada29b718a87ea0a5cea3fe9a771abdd76bd41a3e545',
95
143
  },
144
+ {
145
+ dex: v3_dex_types_1.UniswapV3StyleDexEnum.PHARAOH_CLMM, // reuse existing UNISWAP_V3 branch/ABIs
146
+ router: '0x062c62cA66E50Cfe277A95564Fe5bB504db1Fab8', // SwapRouter (immutable & verified)
147
+ quoter: '0xAAAEA10b0e6FBe566FE27c3A023DC5D8cA6Bca3d', // QuoterV2
148
+ factory: '0xAAA32926fcE6bE95ea2c51cB4Fcb60836D320C42', // PharaohV2Factory (CL)
149
+ initHash: '0x1565b129f2d1790f12d45301b9b084335626f0c92410bc43130763b69971135d',
150
+ },
96
151
  // {
97
152
  // dex: UniswapV3StyleDexEnum.SUSHISWAP_V3,
98
153
  // router: '0x81602ef321c46d73f5ba7f476947ae1a862957dc', // RouteProcessor9
@@ -159,6 +214,13 @@ class V3StyleDexService {
159
214
  factory: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865',
160
215
  initHash: '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2',
161
216
  },
217
+ {
218
+ dex: v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM,
219
+ quoter: '0x254cF9E1E6e233aa1AC962CB9B05b2cfeAaE15b0',
220
+ router: '0xBE6D8f0d05cC4be24d5167a3eF062215bE6D18a5',
221
+ factory: '0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A',
222
+ initHash: '0xffb9af9ea6d9e39da47392ecc7055277b9915b8bfc9f83f105821b7791a6ae30',
223
+ },
162
224
  // {
163
225
  // dex: UniswapV3StyleDexEnum.SUSHISWAP_V3,
164
226
  // router: '0x81602ef321c46d73f5ba7f476947ae1a862957dc', // RouteProcessor9
@@ -195,6 +257,13 @@ class V3StyleDexService {
195
257
  factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
196
258
  initHash: '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54',
197
259
  },
260
+ {
261
+ dex: v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM,
262
+ quoter: '0x89D8218ed5fF1e46d8dcd33fb0bbeE3be1621466',
263
+ router: '0x0792a633F0c19c351081CF4B211F68F79bCc9676',
264
+ factory: '0xCc0bDDB707055e04e497aB22a59c2aF4391cd12F',
265
+ initHash: '0x339492e30b7a68609e535da9b0773082bfe60230ca47639ee5566007d525f5a7',
266
+ },
198
267
  // {
199
268
  // dex: UniswapV3StyleDexEnum.SUSHISWAP_V3,
200
269
  // router: '0x81602ef321c46d73f5ba7f476947ae1a862957dc', // RouteProcessor9
@@ -272,15 +341,17 @@ class V3StyleDexService {
272
341
  if (!deployments.length) {
273
342
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `No V3-style deployments configured for network ${networkIn}`);
274
343
  }
344
+ // Early exit if caller supplied a known pair & minOut (optimistic path)
275
345
  if (pair && expectedAmountOutMin && dex) {
276
- /**
277
- * Use the dex enum to find the corresponding router given the networkIn
278
- */
279
346
  const router = deployments.find(d => d.dex === dex)?.router;
280
347
  if (!router) {
281
348
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `No router found for dex ${dex} on chainId ${networkIn}`);
282
349
  }
283
- const dexKey = this._buildDexKey(networkIn, router);
350
+ const dexKey = (0, dex_deployment_key_1.dexDeploymentKey)({
351
+ dex: dex,
352
+ router: router,
353
+ network: networkIn,
354
+ });
284
355
  const earlyResponse = {
285
356
  dex: dexKey,
286
357
  amountOut: expectedAmountOutMin,
@@ -293,7 +364,7 @@ class V3StyleDexService {
293
364
  path: pair,
294
365
  notes: `Early return due to supplied pair and amountOutMin`,
295
366
  };
296
- const priceResponse = {
367
+ return {
297
368
  protocol: this.protocol,
298
369
  networkIn,
299
370
  networkOut,
@@ -304,11 +375,9 @@ class V3StyleDexService {
304
375
  slippage,
305
376
  protocolResponse: earlyResponse,
306
377
  };
307
- return priceResponse;
308
378
  }
309
379
  const client = this._clients[networkIn];
310
380
  if (!client) {
311
- console.log(`No RPC client configured for chainId ${networkIn}`);
312
381
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `No RPC client configured for chainId ${networkIn}`);
313
382
  }
314
383
  // === Native <-> Wrapped normalization ===
@@ -316,7 +385,6 @@ class V3StyleDexService {
316
385
  const nativeOut = (0, is_native_1.isNative)(tokenOut);
317
386
  const wrapped = wrapped_native_1.wrappedNativeTokens[networkIn];
318
387
  if ((nativeIn || nativeOut) && !wrapped) {
319
- console.log(`No wrapped native token mapping for chainId ${networkIn}`);
320
388
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `Missing wrapped native token mapping for chainId ${networkIn}`);
321
389
  }
322
390
  const tokenInForQuote = nativeIn ? wrapped : tokenIn;
@@ -349,10 +417,37 @@ class V3StyleDexService {
349
417
  const orthodox = deployments.filter(d => !!d.quoter);
350
418
  const quoterless = deployments.filter(d => !('quoter' in d) || !d.quoter);
351
419
  let best;
420
+ // Helper: execute a batch (multicall vs per-call for HyperEVM)
421
+ const execBatch = async (contracts) => {
422
+ if (!contracts.length)
423
+ return [];
424
+ if (networkIn === enums_1.ChainIdEnum.HYPEREVM) {
425
+ return Promise.all(contracts.map(async (c) => {
426
+ try {
427
+ const result = await client.readContract({
428
+ address: c.address,
429
+ abi: c.abi,
430
+ functionName: c.functionName,
431
+ args: c.args,
432
+ });
433
+ return { status: 'success', result };
434
+ }
435
+ catch (error) {
436
+ return { status: 'failure', error };
437
+ }
438
+ }));
439
+ }
440
+ return client.multicall({ allowFailure: true, contracts });
441
+ };
352
442
  /** ---------------------------------------
353
- * Round 1: QuoterV2.quoteExactInputSingle
443
+ * Round 1: QuoterV2-style calls
444
+ * - Uni/Pancake/Pangolin/etc: use fee (uint24)
445
+ * - Slipstream (Velodrome/Aerodrome): use tickSpacing (int24)
354
446
  * ------------------------------------- */
355
- const v2Contracts = orthodox.flatMap(d => {
447
+ // A) Uni-like group (fee tiers)
448
+ const v2ContractsUniLike = orthodox
449
+ .filter(d => !this._isSlipstreamDexString(d.dex))
450
+ .flatMap(d => {
356
451
  const feeTiers = this._determineFeeTiersForDex(d.dex);
357
452
  return feeTiers.map(fee => ({
358
453
  address: d.quoter,
@@ -369,104 +464,136 @@ class V3StyleDexService {
369
464
  ],
370
465
  }));
371
466
  });
372
- const v2Metas = orthodox.flatMap(d => {
467
+ const v2MetasUniLike = orthodox
468
+ .filter(d => !this._isSlipstreamDexString(d.dex))
469
+ .flatMap(d => {
373
470
  const feeTiers = this._determineFeeTiersForDex(d.dex);
374
471
  return feeTiers.map(fee => ({
375
- dex: this._buildDexKey(networkIn, d.router),
472
+ dex: (0, dex_deployment_key_1.dexDeploymentKey)({
473
+ dex: d.dex,
474
+ network: networkIn,
475
+ router: d.router,
476
+ }),
376
477
  fee,
377
478
  quoter: d.quoter,
378
479
  method: 'QuoterV2.quoteExactInputSingle',
480
+ isSlip: false,
481
+ }));
482
+ });
483
+ // B) Slipstream group (tick spacing)
484
+ const v2ContractsSlip = orthodox
485
+ .filter(d => this._isSlipstreamDexString(d.dex))
486
+ .flatMap(d => {
487
+ const tss = this._determineTickSpacingsForDex(d.dex);
488
+ return tss.map(ts => ({
489
+ address: d.quoter,
490
+ abi: slipstream_quoter_abi_1.slipstreamQuoterAbi,
491
+ functionName: 'quoteExactInputSingle',
492
+ args: [
493
+ {
494
+ tokenIn: (0, viem_1.getAddress)(tokenInForQuote),
495
+ tokenOut: (0, viem_1.getAddress)(tokenOutForQuote),
496
+ amountIn: amountInBI,
497
+ tickSpacing: ts,
498
+ sqrtPriceLimitX96: 0n,
499
+ },
500
+ ],
379
501
  }));
380
502
  });
381
- let v2Results;
382
- if (networkIn === enums_1.ChainIdEnum.HYPEREVM) {
383
- // Use individual calls with Promise.all for HyperEVM due to 30M gas limit
384
- v2Results = await Promise.all(v2Contracts.map(async (contract) => {
503
+ const v2MetasSlip = orthodox
504
+ .filter(d => this._isSlipstreamDexString(d.dex))
505
+ .flatMap(d => this._determineTickSpacingsForDex(d.dex).map(ts => ({
506
+ dex: (0, dex_deployment_key_1.dexDeploymentKey)({
507
+ dex: d.dex,
508
+ network: networkIn,
509
+ router: d.router,
510
+ }),
511
+ fee: ts, // store tickSpacing in "fee" slot to reuse payload shape
512
+ quoter: d.quoter,
513
+ method: 'QuoterV2.quoteExactInputSingle',
514
+ isSlip: true,
515
+ })));
516
+ // Execute both groups
517
+ const [v2ResultsUniLike, v2ResultsSlip] = await Promise.all([
518
+ execBatch(v2ContractsUniLike),
519
+ execBatch(v2ContractsSlip),
520
+ ]);
521
+ // Unified handling for success/revert-decode
522
+ const handleV2Group = (results, metas, abi) => {
523
+ for (let i = 0; i < results.length; i++) {
524
+ const res = results[i];
525
+ const meta = metas[i];
526
+ if (!res || !meta)
527
+ continue;
528
+ // success path
529
+ if (res.status === 'success' && Array.isArray(res.result)) {
530
+ const [amountOut, sqrtAfter, ticks, gas] = res.result;
531
+ const candidate = {
532
+ amountOut,
533
+ payload: {
534
+ dex: meta.dex,
535
+ quoterAddress: meta.quoter,
536
+ method: meta.method,
537
+ feeTier: meta.fee, // NOTE: tickSpacing for Slipstream
538
+ amountOut: amountOut.toString(),
539
+ gasEstimate: gas ? gas.toString() : undefined,
540
+ sqrtPriceX96After: sqrtAfter ? sqrtAfter.toString() : undefined,
541
+ initializedTicksCrossed: ticks,
542
+ notes: (meta.isSlip ? 'Slipstream tickSpacing; ' : '') +
543
+ (nativeIn || nativeOut
544
+ ? `Quoted with wrapped native: in=${nativeIn ? 'wrapped' : 'erc20'}, out=${nativeOut ? 'wrapped' : 'erc20'}`
545
+ : ''),
546
+ },
547
+ };
548
+ if (!best || candidate.amountOut > best.amountOut)
549
+ best = candidate;
550
+ continue;
551
+ }
552
+ // revert decode (some quoters return data on revert)
553
+ // @ts-ignore – Viem surfaces revert data in error.data
554
+ const data = res?.error?.data;
555
+ if (!data || data === '0x')
556
+ continue;
385
557
  try {
386
- const result = await client.readContract({
387
- address: contract.address,
388
- abi: contract.abi,
389
- functionName: contract.functionName,
390
- args: contract.args,
558
+ const [amountOut, sqrtAfter, ticks, gas] = (0, viem_1.decodeFunctionResult)({
559
+ abi,
560
+ functionName: 'quoteExactInputSingle',
561
+ data,
391
562
  });
392
- return { status: 'success', result };
563
+ const candidate = {
564
+ amountOut,
565
+ payload: {
566
+ dex: meta.dex,
567
+ quoterAddress: meta.quoter,
568
+ method: meta.method,
569
+ feeTier: meta.fee, // NOTE: tickSpacing for Slipstream
570
+ amountOut: amountOut.toString(),
571
+ gasEstimate: gas ? gas.toString() : undefined,
572
+ sqrtPriceX96After: sqrtAfter ? sqrtAfter.toString() : undefined,
573
+ initializedTicksCrossed: ticks,
574
+ notes: (meta.isSlip ? 'Slipstream tickSpacing; ' : '') +
575
+ (nativeIn || nativeOut
576
+ ? `Quoted with wrapped native: in=${nativeIn ? 'wrapped' : 'erc20'}, out=${nativeOut ? 'wrapped' : 'erc20'}`
577
+ : ''),
578
+ },
579
+ };
580
+ if (!best || candidate.amountOut > (best.amountOut ?? 0n))
581
+ best = candidate;
393
582
  }
394
- catch (error) {
395
- return { status: 'failure', error };
583
+ catch {
584
+ /* ignore; continue */
396
585
  }
397
- }));
398
- }
399
- else {
400
- v2Results = v2Contracts.length
401
- ? await client.multicall({ allowFailure: true, contracts: v2Contracts })
402
- : [];
403
- }
404
- for (let i = 0; i < v2Results.length; i++) {
405
- const res = v2Results[i];
406
- const meta = v2Metas[i];
407
- if (!res || !meta)
408
- continue;
409
- if (res.status === 'success' && Array.isArray(res.result)) {
410
- const [amountOut, sqrtAfter, ticks, gas] = res.result;
411
- const candidate = {
412
- amountOut,
413
- payload: {
414
- dex: meta.dex,
415
- quoterAddress: meta.quoter,
416
- method: meta.method,
417
- feeTier: meta.fee,
418
- amountOut: amountOut.toString(),
419
- gasEstimate: gas ? gas.toString() : undefined,
420
- sqrtPriceX96After: sqrtAfter ? sqrtAfter.toString() : undefined,
421
- initializedTicksCrossed: ticks,
422
- notes: nativeIn || nativeOut
423
- ? `Quoted with wrapped native: in=${nativeIn ? 'wrapped' : 'erc20'}, out=${nativeOut ? 'wrapped' : 'erc20'}`
424
- : undefined,
425
- },
426
- };
427
- if (!best || candidate.amountOut > best.amountOut)
428
- best = candidate;
429
- continue;
430
- }
431
- // Try to decode revert (some quoters return data on revert)
432
- // @ts-ignore – Viem surfaces revert data in error.data
433
- const data = res?.error?.data;
434
- if (!data || data === '0x')
435
- continue;
436
- try {
437
- const [amountOut, sqrtAfter, ticks, gas] = (0, viem_1.decodeFunctionResult)({
438
- abi: uniswapV3_quoter_abi_1.uniswapV3QuoterAbi,
439
- functionName: 'quoteExactInputSingle',
440
- data,
441
- });
442
- const candidate = {
443
- amountOut,
444
- payload: {
445
- dex: meta.dex,
446
- quoterAddress: meta.quoter,
447
- method: meta.method,
448
- feeTier: meta.fee,
449
- amountOut: amountOut.toString(),
450
- gasEstimate: gas ? gas.toString() : undefined,
451
- sqrtPriceX96After: sqrtAfter ? sqrtAfter.toString() : undefined,
452
- initializedTicksCrossed: ticks,
453
- notes: nativeIn || nativeOut
454
- ? `Quoted with wrapped native: in=${nativeIn ? 'wrapped' : 'erc20'}, out=${nativeOut ? 'wrapped' : 'erc20'}`
455
- : undefined,
456
- },
457
- };
458
- if (!best || candidate.amountOut > (best.amountOut ?? 0n))
459
- best = candidate;
460
- }
461
- catch {
462
- /* ignore; fallback below */
463
586
  }
464
- }
587
+ };
588
+ handleV2Group(v2ResultsUniLike, v2MetasUniLike, uniswapV3_quoter_abi_1.uniswapV3QuoterAbi);
589
+ handleV2Group(v2ResultsSlip, v2MetasSlip, slipstream_quoter_abi_1.slipstreamQuoterAbi);
465
590
  /** ---------------------------------------
466
- * Round 2: Quoter (v1) fallback if needed
591
+ * Round 2: Legacy Quoter (tuple) fallback
592
+ * - Only for Uni-like deployments (Slipstream has no v1 tuple form)
467
593
  * ------------------------------------- */
468
594
  if (!best) {
469
- const v1Contracts = orthodox.flatMap(d => {
595
+ const orthodoxUniLike = orthodox.filter(d => !this._isSlipstreamDexString(d.dex));
596
+ const v1Contracts = orthodoxUniLike.flatMap(d => {
470
597
  const feeTiers = this._determineFeeTiersForDex(d.dex);
471
598
  return feeTiers.map(fee => ({
472
599
  address: d.quoter,
@@ -476,22 +603,23 @@ class V3StyleDexService {
476
603
  {
477
604
  tokenIn: (0, viem_1.getAddress)(tokenInForQuote),
478
605
  tokenOut: (0, viem_1.getAddress)(tokenOutForQuote),
479
- amountIn: amountInBI,
480
606
  fee,
607
+ amountIn: amountInBI,
481
608
  sqrtPriceLimitX96: 0n,
482
609
  },
483
610
  ],
484
611
  }));
485
612
  });
486
- const v1Metas = orthodox.flatMap(d => {
487
- const feeTiers = this._determineFeeTiersForDex(d.dex);
488
- return feeTiers.map(fee => ({
489
- dex: this._buildDexKey(networkIn, d.router),
490
- fee,
491
- quoter: d.quoter,
492
- method: 'Quoter.quoteExactInputSingle',
493
- }));
494
- });
613
+ const v1Metas = orthodoxUniLike.flatMap(d => this._determineFeeTiersForDex(d.dex).map(fee => ({
614
+ dex: (0, dex_deployment_key_1.dexDeploymentKey)({
615
+ dex: d.dex,
616
+ network: networkIn,
617
+ router: d.router,
618
+ }),
619
+ fee,
620
+ quoter: d.quoter,
621
+ method: 'Quoter.quoteExactInputSingle',
622
+ })));
495
623
  const v1Results = v1Contracts.length
496
624
  ? await client.multicall({
497
625
  allowFailure: true,
@@ -553,23 +681,21 @@ class V3StyleDexService {
553
681
  best = candidate;
554
682
  }
555
683
  catch {
556
- /* ignore; no more fallbacks */
684
+ /* ignore */
557
685
  }
558
686
  }
559
687
  }
560
688
  /** ---------------------------------------
561
- * Round 3: Off-chain quoter (no quoter deployments, e.g., Sushi V3)
689
+ * Round 3: Off-chain quoter (no on-chain quoter)
562
690
  * ------------------------------------- */
563
691
  {
564
- // Only consider quoter-less deployments that ALSO provide a factory address in config/uniV3ExtraDeployments.
565
- // (If factory is absent, we cannot discover pools; we skip those entries.)
566
692
  const offchainCapable = quoterless.filter(d => !!d?.factory);
567
693
  if (offchainCapable.length) {
568
694
  const offchain = new v3_offchain_quoter_service_1.V3OffchainQuoter();
569
- // sequential to keep RPC load predictable across many tiers/words;
570
- // user can parallelize externally if desired
571
695
  for (const d of offchainCapable) {
572
696
  try {
697
+ // For off-chain we keep fee tiers (Uni-like). Slipstream off-chain
698
+ // could be added later by scanning tickSpacing set; omitted here intentionally.
573
699
  const res = await offchain.fetchV3Quote({
574
700
  client,
575
701
  tokenIn: (0, viem_1.getAddress)(tokenInForQuote),
@@ -577,16 +703,18 @@ class V3StyleDexService {
577
703
  amountIn: amountInBI,
578
704
  factory: (0, viem_1.getAddress)(d.factory),
579
705
  fees: this.uniFeeTiers,
580
- // optional safety knobs can be wired via UniV3Config in the future:
581
- // maxTickReads, prefetchWords
582
706
  });
583
707
  if (res?.best && res.best.ok && res.best.amountOut > 0n) {
584
- const dexKey = this._buildDexKey(networkIn, d.router);
708
+ const dexKey = (0, dex_deployment_key_1.dexDeploymentKey)({
709
+ network: networkIn,
710
+ router: d.router,
711
+ dex: d.dex,
712
+ });
585
713
  const candidate = {
586
714
  amountOut: res.best.amountOut,
587
715
  payload: {
588
716
  dex: dexKey,
589
- quoterAddress: undefined, // no on-chain quoter used
717
+ quoterAddress: undefined,
590
718
  method: 'OffchainQuoter.simulateExactInputSingle',
591
719
  feeTier: res.best.fee,
592
720
  amountOut: res.best.amountOut.toString(),
@@ -610,7 +738,7 @@ class V3StyleDexService {
610
738
  }
611
739
  }
612
740
  if (!best) {
613
- throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.QUOTE_NOT_FOUND, `No UniswapV3 style quote could be found`);
741
+ throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.QUOTE_NOT_FOUND, `No V3-style quote could be found`);
614
742
  }
615
743
  return {
616
744
  protocol: this.protocol,
@@ -655,7 +783,7 @@ class V3StyleDexService {
655
783
  }
656
784
  const tokenInExec = (expectNativeIn ? wrapped : tokenIn);
657
785
  const tokenOutExec = (expectNativeOut ? wrapped : tokenOut);
658
- // Price discovery (now includes off-chain fallback for quoter-less deployments)
786
+ // Price discovery (now includes Slipstream tickSpacing handling via fetchPrice)
659
787
  let v3Price;
660
788
  if (!params?.priceResponse) {
661
789
  let priceRes;
@@ -677,18 +805,20 @@ class V3StyleDexService {
677
805
  }
678
806
  v3Price = priceRes.protocolResponse;
679
807
  }
808
+ else {
809
+ v3Price = params.priceResponse.protocolResponse;
810
+ }
680
811
  if (!v3Price || !v3Price.amountOut || v3Price.amountOut === '0') {
681
812
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.QUOTE_NOT_FOUND, 'No V3-style quote could be found');
682
813
  }
683
814
  // Slippage handling (percent)
684
815
  const bestAmountOut = BigInt(v3Price.amountOut);
685
816
  const slippagePct = typeof slippage === 'number' ? slippage : Number(slippage || 0);
686
- const amountOutMin = slippagePct > 0
687
- ? (bestAmountOut * BigInt(Math.floor((100 - slippagePct) * 1000000))) / 100000000n
688
- : bestAmountOut;
817
+ const amountOutMin = (0, min_amount_out_1.calculateMinAmountOut)({
818
+ amountOut: bestAmountOut.toString(),
819
+ slippage: slippagePct,
820
+ });
689
821
  // Router resolution:
690
- // - If quoterAddress is present, match router by that quoter's deployment
691
- // - Else (off-chain path), pick any deployment with the same dex id that has a router
692
822
  const deployments = this.deployments[networkIn] ?? [];
693
823
  let chosenRouter;
694
824
  if (v3Price.quoterAddress) {
@@ -701,7 +831,6 @@ class V3StyleDexService {
701
831
  chosenRouter = maybeRouter;
702
832
  }
703
833
  if (!chosenRouter) {
704
- // final fallback: any router on this network (highly unlikely to hit)
705
834
  chosenRouter = deployments.find(d => !!d.router)?.router;
706
835
  }
707
836
  if (!chosenRouter) {
@@ -714,6 +843,9 @@ class V3StyleDexService {
714
843
  const isSushiV3 = this._isDex(v3_dex_types_1.UniswapV3StyleDexEnum.SUSHISWAP_V3, v3Price);
715
844
  const isPancakeV3 = this._isDex(v3_dex_types_1.UniswapV3StyleDexEnum.PANCAKESWAP_V3, v3Price);
716
845
  const isPangolinV3 = this._isDex(v3_dex_types_1.UniswapV3StyleDexEnum.PANGOLIN_V3, v3Price);
846
+ const isPharaoh = this._isDex(v3_dex_types_1.UniswapV3StyleDexEnum.PHARAOH_CLMM, v3Price);
847
+ const isSlipstream = this._isDex(v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM, v3Price) ||
848
+ this._isDex(v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM, v3Price);
717
849
  let data;
718
850
  let methodForResponse;
719
851
  let txValue = expectNativeIn ? amountInBI.toString() : '0';
@@ -722,51 +854,42 @@ class V3StyleDexService {
722
854
  * -------------------------
723
855
  * Sushi Route Processor 9
724
856
  * -------------------------
725
- * We target `processRoute`-family methods depending on native input:
726
- * - Native in (expectNativeIn): use `processRouteWithTransferValueInput` (payable) so we can pass msg.value.
727
- * - ERC20 in: use `processRoute` (no value transfer needed).
728
- *
729
- * NOTE: `route` bytes are expected to be produced off-chain (e.g., Sushi Tines pathfinder).
730
- * Here we set it to `0x` as a sentinel; upstream code should replace with a valid route prior to execution.
731
- * If your pipeline already has the route bytes available at this stage, replace `routeBytes` accordingly.
857
+ * Uses route bytes (off-chain). We set a sentinel here.
732
858
  */
733
859
  const routeBytes = '0x';
734
860
  const takeSurplus = false;
735
861
  const referralCode = 0;
736
862
  if (expectNativeIn) {
737
- // Payable path: send msg.value and call *WithTransferValueInput*
738
- // We forward value to the RP9 itself (common pattern); adjust if you have a dedicated treasury.
739
863
  data = (0, viem_1.encodeFunctionData)({
740
864
  abi: sushiswap_route_processor_9_abi_1.sushiswapRouteProcessor9Abi,
741
865
  functionName: 'processRouteWithTransferValueInput',
742
866
  args: [
743
- (0, viem_1.getAddress)(chosenRouter), // transferValueTo
867
+ (0, viem_1.getAddress)(chosenRouter), // transferValueTo (RP9)
744
868
  amountInBI, // amountValueTransfer
745
- (0, viem_1.getAddress)(tokenInExec), // tokenIn (wrapped native is fine; RP9/tines route may unwrap/rewrap as needed)
746
- amountInBI, // amountIn
747
- (0, viem_1.getAddress)(tokenOutExec), // tokenOut (use wrapped if nativeOut; route should handle unwrap if desired)
748
- amountOutMin, // amountOutQuote
749
- (0, viem_1.getAddress)(receiver || from), // to
750
- routeBytes, // route (to be produced off-chain)
869
+ (0, viem_1.getAddress)(tokenInExec),
870
+ amountInBI,
871
+ (0, viem_1.getAddress)(tokenOutExec),
872
+ amountOutMin,
873
+ (0, viem_1.getAddress)(receiver || from),
874
+ routeBytes,
751
875
  takeSurplus,
752
876
  referralCode,
753
877
  ],
754
878
  });
755
879
  methodForResponse = 'RouteProcessor9.processRouteWithTransferValueInput';
756
- // txValue already set to amountInBI for native-in case
880
+ // txValue already equals amountIn for native-in
757
881
  }
758
882
  else {
759
- // ERC-20 in: no msg.value required; standard processRoute
760
883
  data = (0, viem_1.encodeFunctionData)({
761
884
  abi: sushiswap_route_processor_9_abi_1.sushiswapRouteProcessor9Abi,
762
885
  functionName: 'processRoute',
763
886
  args: [
764
- (0, viem_1.getAddress)(tokenInExec), // tokenIn
765
- amountInBI, // amountIn
766
- (0, viem_1.getAddress)(tokenOutExec), // tokenOut
767
- amountOutMin, // amountOutQuote
768
- (0, viem_1.getAddress)(receiver || from), // to
769
- routeBytes, // route (to be produced off-chain)
887
+ (0, viem_1.getAddress)(tokenInExec),
888
+ amountInBI,
889
+ (0, viem_1.getAddress)(tokenOutExec),
890
+ amountOutMin,
891
+ (0, viem_1.getAddress)(receiver || from),
892
+ routeBytes,
770
893
  takeSurplus,
771
894
  referralCode,
772
895
  ],
@@ -776,32 +899,60 @@ class V3StyleDexService {
776
899
  }
777
900
  }
778
901
  else {
779
- const routerAbi = isPancakeV3 || isPangolinV3 ? pacakeswapV3_router_abi_1.pancakeswapV3RouterAbi : uniswapV3_router_abi_1.uniswapV3RouterAbi;
780
- const struct = isPancakeV3 || isPangolinV3
781
- ? {
902
+ // Choose router ABI (Slipstream vs Uni-like)
903
+ const routerAbi = isSlipstream
904
+ ? slipstream_router_abi_1.slipstreamRouterAbi
905
+ : isPancakeV3 || isPangolinV3 || isPharaoh
906
+ ? pacakeswapV3_router_abi_1.pancakeswapV3RouterAbi
907
+ : uniswapV3_router_abi_1.uniswapV3RouterAbi;
908
+ // Build exactInputSingle calldata
909
+ let exactInputSingleCalldata;
910
+ if (isSlipstream) {
911
+ // Slipstream uses tickSpacing (int24) and includes deadline in the struct
912
+ const struct = {
782
913
  tokenIn: (0, viem_1.getAddress)(tokenInExec),
783
914
  tokenOut: (0, viem_1.getAddress)(tokenOutExec),
784
- fee: (v3Price.feeTier ?? 3000),
915
+ tickSpacing: Number(v3Price.feeTier ?? 60), // feeTier carries tickSpacing for Slipstream
785
916
  recipient: recipientForFirstLeg,
786
917
  deadline,
787
918
  amountIn: amountInBI,
788
919
  amountOutMinimum: amountOutMin,
789
920
  sqrtPriceLimitX96: 0n,
790
- }
791
- : {
792
- tokenIn: (0, viem_1.getAddress)(tokenInExec),
793
- tokenOut: (0, viem_1.getAddress)(tokenOutExec),
794
- fee: (v3Price.feeTier ?? 3000),
795
- recipient: recipientForFirstLeg,
796
- amountIn: amountInBI,
797
- amountOutMinimum: amountOutMin,
798
- sqrtPriceLimitX96: 0n,
799
921
  };
800
- const exactInputSingleCalldata = (0, viem_1.encodeFunctionData)({
801
- abi: routerAbi,
802
- functionName: 'exactInputSingle',
803
- args: [struct],
804
- });
922
+ exactInputSingleCalldata = (0, viem_1.encodeFunctionData)({
923
+ abi: routerAbi,
924
+ functionName: 'exactInputSingle',
925
+ args: [struct],
926
+ });
927
+ }
928
+ else {
929
+ // Uni/Pancake/Pangolin use fee (uint24)
930
+ const struct = isPancakeV3 || isPangolinV3 || isPharaoh
931
+ ? {
932
+ tokenIn: (0, viem_1.getAddress)(tokenInExec),
933
+ tokenOut: (0, viem_1.getAddress)(tokenOutExec),
934
+ fee: (v3Price.feeTier ?? 3000),
935
+ recipient: recipientForFirstLeg,
936
+ deadline,
937
+ amountIn: amountInBI,
938
+ amountOutMinimum: amountOutMin,
939
+ sqrtPriceLimitX96: 0n,
940
+ }
941
+ : {
942
+ tokenIn: (0, viem_1.getAddress)(tokenInExec),
943
+ tokenOut: (0, viem_1.getAddress)(tokenOutExec),
944
+ fee: (v3Price.feeTier ?? 3000),
945
+ recipient: recipientForFirstLeg,
946
+ amountIn: amountInBI,
947
+ amountOutMinimum: amountOutMin,
948
+ sqrtPriceLimitX96: 0n,
949
+ };
950
+ exactInputSingleCalldata = (0, viem_1.encodeFunctionData)({
951
+ abi: routerAbi,
952
+ functionName: 'exactInputSingle',
953
+ args: [struct],
954
+ });
955
+ }
805
956
  if (expectNativeOut) {
806
957
  const unwrapCalldata = (0, viem_1.encodeFunctionData)({
807
958
  abi: routerAbi,
@@ -821,10 +972,6 @@ class V3StyleDexService {
821
972
  }
822
973
  }
823
974
  // ETH value handling:
824
- // - For Sushi RP9 branch with native in: msg.value == amountIn
825
- // - For UniV3 branch with native in: msg.value == amountIn
826
- // - Else: 0
827
- // (txValue already assigned above)
828
975
  const approval = expectNativeIn
829
976
  ? undefined
830
977
  : {
@@ -847,6 +994,7 @@ class V3StyleDexService {
847
994
  if (!deployment) {
848
995
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `No deployment found for dex ${dexEnum} on network ${networkIn}.`);
849
996
  }
997
+ // CREATE2 pair computation:
850
998
  const pairAddress = this._create2Address({
851
999
  dex: dexEnum,
852
1000
  factory: deployment?.factory,
@@ -854,14 +1002,14 @@ class V3StyleDexService {
854
1002
  initHash: deployment?.initHash,
855
1003
  tokenA: tokenInExec,
856
1004
  tokenB: tokenOutExec,
857
- fee: v3Price.feeTier,
1005
+ fee: v3Price.feeTier, // NOTE: for Slipstream this is tickSpacing (int24)
858
1006
  });
859
1007
  const protocolResponse = {
860
1008
  dex: v3Price.dex,
861
1009
  pair: (0, viem_1.getAddress)(pairAddress),
862
1010
  routerAddress: chosenRouter,
863
- quoterAddress: v3Price.quoterAddress, // undefined for off-chain path
864
- feeTier: v3Price.feeTier,
1011
+ quoterAddress: v3Price.quoterAddress,
1012
+ feeTier: v3Price.feeTier, // tickSpacing for Slipstream
865
1013
  method: methodForResponse,
866
1014
  amountOut: bestAmountOut.toString(),
867
1015
  amountOutMin: amountOutMin.toString(),
@@ -871,13 +1019,14 @@ class V3StyleDexService {
871
1019
  sqrtPriceX96After: v3Price.sqrtPriceX96After,
872
1020
  initializedTicksCrossed: v3Price.initializedTicksCrossed,
873
1021
  notes: (v3Price.method?.startsWith('OffchainQuoter') ? 'Off-chain pool simulation; ' : '') +
1022
+ (isSlipstream ? 'Slipstream tickSpacing; ' : '') +
874
1023
  (isSushiV3
875
1024
  ? 'Sushi Route Processor 9 calldata (route bytes expected from off-chain pathfinder); '
876
1025
  : '') +
877
1026
  (expectNativeIn ? 'Native in; ' : '') +
878
1027
  (expectNativeOut
879
1028
  ? isSushiV3
880
- ? 'Native out should be handled inside route bytes.'
1029
+ ? 'Native out handled inside route bytes.'
881
1030
  : 'Native out via multicall(unwrapWETH9).'
882
1031
  : 'ERC-20 out to recipient.'),
883
1032
  };
@@ -897,14 +1046,6 @@ class V3StyleDexService {
897
1046
  protocolResponse,
898
1047
  };
899
1048
  }
900
- _buildDexKey(network, router) {
901
- // Find the deployment from `deployments` where the router address is equal to the router param
902
- const deployment = this.deployments[network]?.find(d => d.router.toLowerCase() === router.toLowerCase());
903
- if (!deployment) {
904
- throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `No deployment found for router ${router} on network ${network}.`);
905
- }
906
- return `${deployment.dex}:${router}:${network}`;
907
- }
908
1049
  _convertKeyToDexEnum(dexKey) {
909
1050
  const parts = dexKey.split(':');
910
1051
  if (parts.length !== 3) {
@@ -917,6 +1058,9 @@ class V3StyleDexService {
917
1058
  v3_dex_types_1.UniswapV3StyleDexEnum.PANCAKESWAP_V3,
918
1059
  v3_dex_types_1.UniswapV3StyleDexEnum.PANGOLIN_V3,
919
1060
  v3_dex_types_1.UniswapV3StyleDexEnum.HYPERSWAP_V3,
1061
+ v3_dex_types_1.UniswapV3StyleDexEnum.PHARAOH_CLMM,
1062
+ v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM,
1063
+ v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM,
920
1064
  ].includes(dexEnum)) {
921
1065
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `Unknown dex enum in key: ${dexKey}`);
922
1066
  }
@@ -931,7 +1075,13 @@ class V3StyleDexService {
931
1075
  ? v3_dex_types_1.UniswapV3StyleDexEnum.SUSHISWAP_V3
932
1076
  : dexString === v3_dex_types_1.UniswapV3StyleDexEnum.HYPERSWAP_V3
933
1077
  ? v3_dex_types_1.UniswapV3StyleDexEnum.HYPERSWAP_V3
934
- : v3_dex_types_1.UniswapV3StyleDexEnum.UNISWAP_V3;
1078
+ : dexString === v3_dex_types_1.UniswapV3StyleDexEnum.PHARAOH_CLMM
1079
+ ? v3_dex_types_1.UniswapV3StyleDexEnum.PHARAOH_CLMM
1080
+ : dexString === v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM
1081
+ ? v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM
1082
+ : dexString === v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM
1083
+ ? v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM
1084
+ : v3_dex_types_1.UniswapV3StyleDexEnum.UNISWAP_V3;
935
1085
  switch (dex) {
936
1086
  case v3_dex_types_1.UniswapV3StyleDexEnum.PANCAKESWAP_V3:
937
1087
  return this.pancakeFeeTiers;
@@ -941,6 +1091,12 @@ class V3StyleDexService {
941
1091
  return this.uniFeeTiers;
942
1092
  case v3_dex_types_1.UniswapV3StyleDexEnum.HYPERSWAP_V3:
943
1093
  return this.hyperswapFeeTiers;
1094
+ case v3_dex_types_1.UniswapV3StyleDexEnum.PHARAOH_CLMM:
1095
+ return this.pharaohFeeTiers;
1096
+ case v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM:
1097
+ return this.aerodromeFeeTiers;
1098
+ case v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM:
1099
+ return this.velodromeFeeTiers;
944
1100
  case v3_dex_types_1.UniswapV3StyleDexEnum.UNISWAP_V3:
945
1101
  default:
946
1102
  return this.uniFeeTiers;
@@ -951,23 +1107,25 @@ class V3StyleDexService {
951
1107
  }
952
1108
  _create2Address(params) {
953
1109
  const { dex, initHash, tokenA, tokenB, fee, deployer, factory } = params;
1110
+ const isSlip = dex === v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM || dex === v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM;
1111
+ // For Pancake V3 you already special-case deployer vs factory; Slipstream uses factory as deployer.
954
1112
  const addressToUse = dex === v3_dex_types_1.UniswapV3StyleDexEnum.PANCAKESWAP_V3 ? deployer : factory;
955
- // Uniswap/Pancake V3 salt uses token0 < token1 ordering
956
1113
  const a = (0, viem_1.getAddress)(tokenA);
957
1114
  const b = (0, viem_1.getAddress)(tokenB);
958
- const [token0, token1] = a.toLowerCase() < b.toLowerCase() ? [a, b] : [b, a];
959
- // Salt = keccak256(abi.encode(address,address,uint24))
960
- const encoded = (0, viem_1.encodeAbiParameters)([{ type: 'address' }, { type: 'address' }, { type: 'uint24' }], [token0, token1, fee]);
1115
+ const [token0, token1] = (0, sort_addresses_1.sortAddresses)(a, b);
1116
+ // SLIPSTREAM: salt = keccak256(abi.encode(address,address,int24 tickSpacing))
1117
+ // UNI-LIKE: salt = keccak256(abi.encode(address,address,uint24 fee))
1118
+ const encoded = isSlip
1119
+ ? (0, viem_1.encodeAbiParameters)([{ type: 'address' }, { type: 'address' }, { type: 'int24' }], [token0, token1, fee])
1120
+ : (0, viem_1.encodeAbiParameters)([{ type: 'address' }, { type: 'address' }, { type: 'uint24' }], [token0, token1, fee]);
961
1121
  const salt = (0, ethers_1.keccak256)(encoded);
962
- // CREATE2 addr = last 20 bytes of keccak256(0xff ++ addressToUse ++ salt ++ initCodeHash)
963
1122
  const digest = (0, ethers_1.keccak256)((0, viem_1.concat)([
964
1123
  (0, viem_1.hexToBytes)('0xff'),
965
1124
  (0, viem_1.hexToBytes)(addressToUse),
966
1125
  (0, viem_1.hexToBytes)(salt),
967
1126
  (0, viem_1.hexToBytes)(initHash),
968
1127
  ]));
969
- // Take last 20 bytes
970
- return (0, viem_1.getAddress)(`0x${digest.slice(26)}`); // remove '0x' + 24 hex (12 bytes)
1128
+ return (0, viem_1.getAddress)(`0x${digest.slice(26)}`);
971
1129
  }
972
1130
  async _validateNativeLiquidity(params) {
973
1131
  const { tokenIn, networkIn, dexes, nativePrice, tokenInPrice, tokenInDecimals } = params;
@@ -1193,7 +1351,11 @@ class V3StyleDexService {
1193
1351
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.INVALID_PARAMS, `Supplied pair/token direction mismatch. Pair ${pair} tokens are ${token0}/${token1}; received ${tokenInForQuote}/${tokenOutForQuote}`);
1194
1352
  }
1195
1353
  // Build dex key for response routing
1196
- const dexKey = this._buildDexKey(network, deployment.router);
1354
+ const dexKey = (0, dex_deployment_key_1.dexDeploymentKey)({
1355
+ dex: deployment.dex,
1356
+ router: deployment.router,
1357
+ network,
1358
+ });
1197
1359
  // 2) Try on-chain quoter (struct signature first, then legacy)
1198
1360
  if (deployment?.quoter) {
1199
1361
  // V2 (struct)
@@ -1296,6 +1458,20 @@ class V3StyleDexService {
1296
1458
  }
1297
1459
  throw (0, utils_1.sdkError)(enums_1.SdkErrorEnum.QUOTE_NOT_FOUND, `Unable to quote via known pair ${pair}`);
1298
1460
  }
1461
+ _isSlipstreamDexString(dexString) {
1462
+ return (dexString === v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM ||
1463
+ dexString === v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM);
1464
+ }
1465
+ _determineTickSpacingsForDex(dexString) {
1466
+ switch (dexString) {
1467
+ case v3_dex_types_1.UniswapV3StyleDexEnum.AERODROME_CLMM:
1468
+ return this.aerodromeTickSpacings;
1469
+ case v3_dex_types_1.UniswapV3StyleDexEnum.VELODROME_CLMM:
1470
+ return this.velodromeTickSpacings;
1471
+ default:
1472
+ return [];
1473
+ }
1474
+ }
1299
1475
  }
1300
1476
  exports.V3StyleDexService = V3StyleDexService;
1301
1477
  //# sourceMappingURL=v3-dex.service.js.map