@bitflowlabs/core-sdk 2.0.2 → 2.1.3

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 (42) hide show
  1. package/dist/src/BitflowSDK.d.ts +6 -4
  2. package/dist/src/BitflowSDK.js +439 -239
  3. package/dist/src/BitflowSDK.js.map +1 -1
  4. package/dist/src/helpers/callReadOnlyHelper.d.ts +7 -1
  5. package/dist/src/helpers/callReadOnlyHelper.js +201 -26
  6. package/dist/src/helpers/callReadOnlyHelper.js.map +1 -1
  7. package/dist/src/keeper/keeperAPI.js +3 -48
  8. package/dist/src/keeper/keeperAPI.js.map +1 -1
  9. package/dist/src/keeper/types.d.ts +27 -10
  10. package/dist/src/keeper/types.js.map +1 -1
  11. package/dist/src/test/testMethods.js +10 -0
  12. package/dist/src/test/testMethods.js.map +1 -1
  13. package/package.json +2 -1
  14. package/src/BitflowSDK.ts +532 -269
  15. package/src/helpers/callReadOnlyHelper.ts +258 -32
  16. package/src/keeper/keeperAPI.ts +5 -68
  17. package/src/keeper/types.ts +28 -11
  18. package/src/test/testMethods.ts +19 -0
  19. package/dist/src/test-get-user.d.ts +0 -1
  20. package/dist/src/test-get-user.js +0 -77
  21. package/dist/src/test-get-user.js.map +0 -1
  22. package/dist/src/test-keeper-routes.d.ts +0 -1
  23. package/dist/src/test-keeper-routes.js +0 -67
  24. package/dist/src/test-keeper-routes.js.map +0 -1
  25. package/dist/src/test-order.d.ts +0 -1
  26. package/dist/src/test-order.js +0 -71
  27. package/dist/src/test-order.js.map +0 -1
  28. package/dist/src/test-raw-token-response.d.ts +0 -1
  29. package/dist/src/test-raw-token-response.js +0 -79
  30. package/dist/src/test-raw-token-response.js.map +0 -1
  31. package/dist/src/test-sdk.d.ts +0 -1
  32. package/dist/src/test-sdk.js +0 -229
  33. package/dist/src/test-sdk.js.map +0 -1
  34. package/dist/src/test-token.fetch.d.ts +0 -1
  35. package/dist/src/test-token.fetch.js +0 -63
  36. package/dist/src/test-token.fetch.js.map +0 -1
  37. package/src/test-get-user.ts +0 -87
  38. package/src/test-keeper-routes.ts +0 -76
  39. package/src/test-order.ts +0 -81
  40. package/src/test-raw-token-response.ts +0 -124
  41. package/src/test-sdk.ts +0 -262
  42. package/src/test-token.fetch.ts +0 -72
package/src/BitflowSDK.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { STACKS_MAINNET } from "@stacks/network";
2
- import type { StacksProvider } from "@stacks/connect";
1
+ import { STACKS_MAINNET } from '@stacks/network';
2
+ import type { StacksProvider } from '@stacks/connect';
3
3
  import {
4
4
  SwapContext,
5
5
  Token,
@@ -10,14 +10,17 @@ import {
10
10
  RouteQuote,
11
11
  SwapDataParamsAndPostConditions,
12
12
  BitflowSDKConfig,
13
- } from "./types";
14
- import { fetchAllTokensFromAPI } from "./helpers/fetchDataHelper";
15
- import { executeSwapHelper } from "./helpers/callSwapHelper";
16
- import { callReadOnlyFunctionHelper } from "./helpers/callReadOnlyHelper";
17
- import { fetchPossibleSwapsFromAPI } from "./helpers/fetchPossibleSwap";
18
- import { getContractInterfaceAndFunction } from "./helpers/getContractInterfaceAndFunction";
19
- import { configs, validateConfig } from "./config";
20
- import { executeGetParams } from "./helpers/callGetSwapParams";
13
+ } from './types';
14
+ import { fetchAllTokensFromAPI } from './helpers/fetchDataHelper';
15
+ import { executeSwapHelper } from './helpers/callSwapHelper';
16
+ import {
17
+ callReadOnlyFunctionHelper,
18
+ callReadOnlyFunctionHelperWithoutScaling,
19
+ } from './helpers/callReadOnlyHelper';
20
+ import { fetchPossibleSwapsFromAPI } from './helpers/fetchPossibleSwap';
21
+ import { getContractInterfaceAndFunction } from './helpers/getContractInterfaceAndFunction';
22
+ import { configs, validateConfig } from './config';
23
+ import { executeGetParams } from './helpers/callGetSwapParams';
21
24
  import {
22
25
  ActionFunctionArgs,
23
26
  AggregatorRouteData,
@@ -36,7 +39,7 @@ import {
36
39
  GetQuoteResponse,
37
40
  GetUserResponse,
38
41
  KeeperOrderRouteData,
39
- } from "./keeper/types";
42
+ } from './keeper/types';
40
43
  import {
41
44
  cancelGroupOrderAPI,
42
45
  cancelOrderAPI,
@@ -47,7 +50,15 @@ import {
47
50
  getOrderAPI,
48
51
  getQuoteAPI,
49
52
  getUserAPI,
50
- } from "./keeper/keeperAPI";
53
+ } from './keeper/keeperAPI';
54
+
55
+ export const safeStringify = (obj: any, indent = 2) => {
56
+ return JSON.stringify(
57
+ obj,
58
+ (_, value) => (typeof value === 'bigint' ? value.toString() + 'n' : value),
59
+ indent
60
+ );
61
+ };
51
62
 
52
63
  export class BitflowSDK {
53
64
  private context: SwapContext;
@@ -69,21 +80,21 @@ export class BitflowSDK {
69
80
  this.initializeContext();
70
81
  }
71
82
  private async loadConnectDependencies() {
72
- if (typeof window === "undefined") {
83
+ if (typeof window === 'undefined') {
73
84
  throw new Error(
74
- "Connect features are only available in browser environments"
85
+ 'Connect features are only available in browser environments'
75
86
  );
76
87
  }
77
88
 
78
89
  try {
79
- const { getStacksProvider } = await import("@stacks/connect");
90
+ const { getStacksProvider } = await import('@stacks/connect');
80
91
  if (!this.stacksProvider) {
81
92
  this.stacksProvider = await getStacksProvider();
82
93
  }
83
94
  return this.stacksProvider;
84
95
  } catch (error) {
85
- console.error("Error loading Stacks Connect:", error);
86
- throw new Error("Failed to load Stacks Connect dependencies");
96
+ console.error('Error loading Stacks Connect:', error);
97
+ throw new Error('Failed to load Stacks Connect dependencies');
87
98
  }
88
99
  }
89
100
  private async initializeContext(): Promise<void> {
@@ -119,7 +130,7 @@ export class BitflowSDK {
119
130
  if (!this.context.swapOptions[cacheKey]) {
120
131
  this.context.swapOptions[cacheKey] = await fetchPossibleSwapsFromAPI(
121
132
  tokenX,
122
- "KEEPER"
133
+ 'KEEPER'
123
134
  );
124
135
  }
125
136
  return this.context.swapOptions[cacheKey];
@@ -186,7 +197,7 @@ export class BitflowSDK {
186
197
  continue;
187
198
  }
188
199
 
189
- const [contractDeployer, contractName] = contract.split(".");
200
+ const [contractDeployer, contractName] = contract.split('.');
190
201
 
191
202
  if (!this.context.contractInterfaces[contract]) {
192
203
  this.context.contractInterfaces[contract] =
@@ -201,21 +212,21 @@ export class BitflowSDK {
201
212
 
202
213
  const params = { ...parameters };
203
214
 
204
- if ("dx" in params && params.dx === null) {
215
+ if ('dx' in params && params.dx === null) {
205
216
  params.dx = amountInput;
206
- } else if ("dy" in params && params.dy === null) {
217
+ } else if ('dy' in params && params.dy === null) {
207
218
  params.dy = amountInput;
208
- } else if ("amount" in params && params.amount === null) {
219
+ } else if ('amount' in params && params.amount === null) {
209
220
  params.amount = amountInput;
210
- } else if ("amt-in" in params && params["amt-in"] === null) {
211
- params["amt-in"] = amountInput;
212
- } else if ("amt-in-max" in params && params["amt-in-max"] === null) {
213
- params["amt-in-max"] = amountInput;
214
- } else if ("y-amount" in params && params["y-amount"] === null) {
215
- params["y-amount"] = amountInput;
216
- params["x-amount"] = amountInput;
217
- } else if ("x-amount" in params && params["x-amount"] === null) {
218
- params["x-amount"] = amountInput;
221
+ } else if ('amt-in' in params && params['amt-in'] === null) {
222
+ params['amt-in'] = amountInput;
223
+ } else if ('amt-in-max' in params && params['amt-in-max'] === null) {
224
+ params['amt-in-max'] = amountInput;
225
+ } else if ('y-amount' in params && params['y-amount'] === null) {
226
+ params['y-amount'] = amountInput;
227
+ params['x-amount'] = amountInput;
228
+ } else if ('x-amount' in params && params['x-amount'] === null) {
229
+ params['x-amount'] = amountInput;
219
230
  } else {
220
231
  params.dx = amountInput;
221
232
  }
@@ -233,7 +244,7 @@ export class BitflowSDK {
233
244
  this.context
234
245
  );
235
246
 
236
- if (typeof convertedResult === "number" && convertedResult > 0) {
247
+ if (typeof convertedResult === 'number' && convertedResult > 0) {
237
248
  const updatedQuoteData = {
238
249
  ...route.quoteData,
239
250
  parameters: { ...params },
@@ -246,70 +257,70 @@ export class BitflowSDK {
246
257
  amount:
247
258
  params.amount ||
248
259
  params.dx ||
249
- params["amt-in"] ||
250
- params["amt-in-max"] ||
251
- params["y-amount"] ||
252
- params["x-amount"] ||
260
+ params['amt-in'] ||
261
+ params['amt-in-max'] ||
262
+ params['y-amount'] ||
263
+ params['x-amount'] ||
253
264
  params.dy,
254
265
  dx:
255
266
  params.amount ||
256
267
  params.dx ||
257
- params["amt-in"] ||
258
- params["amt-in-max"] ||
259
- params["y-amount"] ||
260
- params["x-amount"] ||
268
+ params['amt-in'] ||
269
+ params['amt-in-max'] ||
270
+ params['y-amount'] ||
271
+ params['x-amount'] ||
261
272
  params.dy,
262
273
  dy:
263
274
  params.amount ||
264
275
  params.dx ||
265
- params["amt-in"] ||
266
- params["amt-in-max"] ||
267
- params["y-amount"] ||
268
- params["x-amount"] ||
276
+ params['amt-in'] ||
277
+ params['amt-in-max'] ||
278
+ params['y-amount'] ||
279
+ params['x-amount'] ||
269
280
  params.dy,
270
- "amt-in":
281
+ 'amt-in':
271
282
  params.amount ||
272
283
  params.dx ||
273
- params["amt-in"] ||
274
- params["amt-in-max"] ||
275
- params["y-amount"] ||
276
- params["x-amount"] ||
284
+ params['amt-in'] ||
285
+ params['amt-in-max'] ||
286
+ params['y-amount'] ||
287
+ params['x-amount'] ||
277
288
  params.dy,
278
- "amt-in-max":
289
+ 'amt-in-max':
279
290
  params.amount ||
280
291
  params.dx ||
281
- params["amt-in"] ||
282
- params["amt-in-max"] ||
283
- params["y-amount"] ||
284
- params["x-amount"] ||
292
+ params['amt-in'] ||
293
+ params['amt-in-max'] ||
294
+ params['y-amount'] ||
295
+ params['x-amount'] ||
285
296
  params.dy,
286
- "y-amount":
297
+ 'y-amount':
287
298
  params.amount ||
288
299
  params.dx ||
289
- params["amt-in"] ||
290
- params["amt-in-max"] ||
291
- params["y-amount"] ||
292
- params["x-amount"] ||
300
+ params['amt-in'] ||
301
+ params['amt-in-max'] ||
302
+ params['y-amount'] ||
303
+ params['x-amount'] ||
293
304
  params.dy,
294
- "x-amount":
305
+ 'x-amount':
295
306
  params.amount ||
296
307
  params.dx ||
297
- params["amt-in"] ||
298
- params["amt-in-max"] ||
299
- params["y-amount"] ||
300
- params["x-amount"] ||
308
+ params['amt-in'] ||
309
+ params['amt-in-max'] ||
310
+ params['y-amount'] ||
311
+ params['x-amount'] ||
301
312
  params.dy,
302
313
 
303
- "min-received": rawResult,
304
- "min-dy": rawResult,
305
- "min-dz": rawResult,
306
- "min-dw": rawResult,
307
- "amt-out": rawResult,
308
- "amt-out-min": rawResult,
309
- "min-x-amount": rawResult,
310
- "min-dv": rawResult,
311
- "min-y-amount": rawResult,
312
- "min-dx": rawResult,
314
+ 'min-received': rawResult,
315
+ 'min-dy': rawResult,
316
+ 'min-dz': rawResult,
317
+ 'min-dw': rawResult,
318
+ 'amt-out': rawResult,
319
+ 'amt-out-min': rawResult,
320
+ 'min-x-amount': rawResult,
321
+ 'min-dv': rawResult,
322
+ 'min-y-amount': rawResult,
323
+ 'min-dx': rawResult,
313
324
  },
314
325
  };
315
326
 
@@ -331,7 +342,7 @@ export class BitflowSDK {
331
342
 
332
343
  allRoutes.push(quoteResult);
333
344
  } else {
334
- throw new Error("Invalid quote result");
345
+ throw new Error('Invalid quote result');
335
346
  }
336
347
  } catch (error) {
337
348
  console.warn(
@@ -373,8 +384,8 @@ export class BitflowSDK {
373
384
  amountInput: number
374
385
  ): Promise<QuoteResult> {
375
386
  const COMPATIBLE_DEX_PATHS = new Set([
376
- "BITFLOW_STABLE_XY_2",
377
- "BITFLOW_XYK_XY_2",
387
+ 'BITFLOW_STABLE_XY_2',
388
+ 'BITFLOW_XYK_XY_2',
378
389
  ]);
379
390
 
380
391
  const isCompatibleRoute = (dexPath: string[]): boolean => {
@@ -414,7 +425,7 @@ export class BitflowSDK {
414
425
  continue;
415
426
  }
416
427
 
417
- const [contractDeployer, contractName] = contract.split(".");
428
+ const [contractDeployer, contractName] = contract.split('.');
418
429
 
419
430
  if (!this.context.contractInterfaces[contract]) {
420
431
  this.context.contractInterfaces[contract] =
@@ -429,21 +440,21 @@ export class BitflowSDK {
429
440
 
430
441
  const params = { ...parameters };
431
442
 
432
- if ("dx" in params && params.dx === null) {
443
+ if ('dx' in params && params.dx === null) {
433
444
  params.dx = amountInput;
434
- } else if ("dy" in params && params.dy === null) {
445
+ } else if ('dy' in params && params.dy === null) {
435
446
  params.dy = amountInput;
436
- } else if ("amount" in params && params.amount === null) {
447
+ } else if ('amount' in params && params.amount === null) {
437
448
  params.amount = amountInput;
438
- } else if ("amt-in" in params && params["amt-in"] === null) {
439
- params["amt-in"] = amountInput;
440
- } else if ("amt-in-max" in params && params["amt-in-max"] === null) {
441
- params["amt-in-max"] = amountInput;
442
- } else if ("y-amount" in params && params["y-amount"] === null) {
443
- params["y-amount"] = amountInput;
444
- params["x-amount"] = amountInput;
445
- } else if ("x-amount" in params && params["x-amount"] === null) {
446
- params["x-amount"] = amountInput;
449
+ } else if ('amt-in' in params && params['amt-in'] === null) {
450
+ params['amt-in'] = amountInput;
451
+ } else if ('amt-in-max' in params && params['amt-in-max'] === null) {
452
+ params['amt-in-max'] = amountInput;
453
+ } else if ('y-amount' in params && params['y-amount'] === null) {
454
+ params['y-amount'] = amountInput;
455
+ params['x-amount'] = amountInput;
456
+ } else if ('x-amount' in params && params['x-amount'] === null) {
457
+ params['x-amount'] = amountInput;
447
458
  } else {
448
459
  params.dx = amountInput;
449
460
  }
@@ -461,7 +472,7 @@ export class BitflowSDK {
461
472
  this.context
462
473
  );
463
474
 
464
- if (typeof convertedResult === "number" && convertedResult > 0) {
475
+ if (typeof convertedResult === 'number' && convertedResult > 0) {
465
476
  const updatedQuoteData = {
466
477
  ...route.quoteData,
467
478
  parameters: { ...params },
@@ -474,61 +485,61 @@ export class BitflowSDK {
474
485
  amount:
475
486
  params.amount ||
476
487
  params.dx ||
477
- params["amt-in"] ||
478
- params["amt-in-max"] ||
479
- params["y-amount"] ||
480
- params["x-amount"] ||
488
+ params['amt-in'] ||
489
+ params['amt-in-max'] ||
490
+ params['y-amount'] ||
491
+ params['x-amount'] ||
481
492
  params.dy,
482
493
  dx:
483
494
  params.amount ||
484
495
  params.dx ||
485
- params["amt-in"] ||
486
- params["amt-in-max"] ||
487
- params["y-amount"] ||
488
- params["x-amount"] ||
496
+ params['amt-in'] ||
497
+ params['amt-in-max'] ||
498
+ params['y-amount'] ||
499
+ params['x-amount'] ||
489
500
  params.dy,
490
- "amt-in":
501
+ 'amt-in':
491
502
  params.amount ||
492
503
  params.dx ||
493
- params["amt-in"] ||
494
- params["amt-in-max"] ||
495
- params["y-amount"] ||
496
- params["x-amount"] ||
504
+ params['amt-in'] ||
505
+ params['amt-in-max'] ||
506
+ params['y-amount'] ||
507
+ params['x-amount'] ||
497
508
  params.dy,
498
- "amt-in-max":
509
+ 'amt-in-max':
499
510
  params.amount ||
500
511
  params.dx ||
501
- params["amt-in"] ||
502
- params["amt-in-max"] ||
503
- params["y-amount"] ||
504
- params["x-amount"] ||
512
+ params['amt-in'] ||
513
+ params['amt-in-max'] ||
514
+ params['y-amount'] ||
515
+ params['x-amount'] ||
505
516
  params.dy,
506
- "y-amount":
517
+ 'y-amount':
507
518
  params.amount ||
508
519
  params.dx ||
509
- params["amt-in"] ||
510
- params["amt-in-max"] ||
511
- params["y-amount"] ||
512
- params["x-amount"] ||
520
+ params['amt-in'] ||
521
+ params['amt-in-max'] ||
522
+ params['y-amount'] ||
523
+ params['x-amount'] ||
513
524
  params.dy,
514
- "x-amount":
525
+ 'x-amount':
515
526
  params.amount ||
516
527
  params.dx ||
517
- params["amt-in"] ||
518
- params["amt-in-max"] ||
519
- params["y-amount"] ||
520
- params["x-amount"] ||
528
+ params['amt-in'] ||
529
+ params['amt-in-max'] ||
530
+ params['y-amount'] ||
531
+ params['x-amount'] ||
521
532
  params.dy,
522
- "min-received": rawResult,
523
- "min-dy": rawResult,
524
- "min-dz": rawResult,
525
- "min-dw": rawResult,
526
- "amt-out": rawResult,
527
- "amt-out-min": rawResult,
528
- "min-x-amount": rawResult,
529
- "min-dv": rawResult,
530
- "min-y-amount": rawResult,
531
- "min-dx": rawResult,
533
+ 'min-received': rawResult,
534
+ 'min-dy': rawResult,
535
+ 'min-dz': rawResult,
536
+ 'min-dw': rawResult,
537
+ 'amt-out': rawResult,
538
+ 'amt-out-min': rawResult,
539
+ 'min-x-amount': rawResult,
540
+ 'min-dv': rawResult,
541
+ 'min-y-amount': rawResult,
542
+ 'min-dx': rawResult,
532
543
  },
533
544
  };
534
545
 
@@ -550,7 +561,7 @@ export class BitflowSDK {
550
561
 
551
562
  allRoutes.push(quoteResult);
552
563
  } else {
553
- throw new Error("Invalid quote result");
564
+ throw new Error('Invalid quote result');
554
565
  }
555
566
  } catch (error) {
556
567
  console.warn(
@@ -585,6 +596,223 @@ export class BitflowSDK {
585
596
  return result;
586
597
  }
587
598
 
599
+ public async getKeeperQuoteForRouteWithoutScaling(
600
+ tokenX: string,
601
+ tokenY: string,
602
+ amountInput: number
603
+ ): Promise<QuoteResult> {
604
+ const COMPATIBLE_DEX_PATHS = new Set([
605
+ 'BITFLOW_STABLE_XY_2',
606
+ 'BITFLOW_XYK_XY_2',
607
+ ]);
608
+
609
+ const isCompatibleRoute = (dexPath: string[]): boolean => {
610
+ return dexPath.every((path) => COMPATIBLE_DEX_PATHS.has(path));
611
+ };
612
+
613
+ let routes = await this.getAllPossibleTokenYRoutes(tokenX, tokenY);
614
+ routes = routes.filter((route) => isCompatibleRoute(route.dex_path));
615
+
616
+ const allRoutes: RouteQuote[] = [];
617
+
618
+ for (let routeIndex = 0; routeIndex < routes.length; routeIndex++) {
619
+ const route = routes[routeIndex];
620
+
621
+ try {
622
+ if (!route.quoteData) {
623
+ console.warn(
624
+ `Skipping route ${routeIndex + 1} due to null quoteData:`,
625
+ route
626
+ );
627
+ continue;
628
+ }
629
+
630
+ const {
631
+ contract,
632
+ function: functionName,
633
+ parameters,
634
+ } = route.quoteData;
635
+
636
+ if (!contract || !functionName || !parameters) {
637
+ console.warn(
638
+ `Skipping route ${
639
+ routeIndex + 1
640
+ } due to missing required properties:`,
641
+ route.quoteData
642
+ );
643
+ continue;
644
+ }
645
+
646
+ const [contractDeployer, contractName] = contract.split('.');
647
+
648
+ if (!this.context.contractInterfaces[contract]) {
649
+ this.context.contractInterfaces[contract] =
650
+ await getContractInterfaceAndFunction(
651
+ contractDeployer,
652
+ contractName,
653
+ functionName
654
+ );
655
+ }
656
+ const { interface: contractInterface, functionArgs } =
657
+ this.context.contractInterfaces[contract];
658
+
659
+ const params = { ...parameters };
660
+
661
+ if ('dx' in params && params.dx === null) {
662
+ params.dx = amountInput;
663
+ } else if ('dy' in params && params.dy === null) {
664
+ params.dy = amountInput;
665
+ } else if ('amount' in params && params.amount === null) {
666
+ params.amount = amountInput;
667
+ } else if ('amt-in' in params && params['amt-in'] === null) {
668
+ params['amt-in'] = amountInput;
669
+ } else if ('amt-in-max' in params && params['amt-in-max'] === null) {
670
+ params['amt-in-max'] = amountInput;
671
+ } else if ('y-amount' in params && params['y-amount'] === null) {
672
+ params['y-amount'] = amountInput;
673
+ params['x-amount'] = amountInput;
674
+ } else if ('x-amount' in params && params['x-amount'] === null) {
675
+ params['x-amount'] = amountInput;
676
+ } else {
677
+ params.dx = amountInput;
678
+ }
679
+
680
+ const { convertedResult, rawResult, tokenXDecimals, tokenYDecimals } =
681
+ await callReadOnlyFunctionHelperWithoutScaling(
682
+ contractDeployer,
683
+ contractName,
684
+ functionName,
685
+ params,
686
+ contractDeployer,
687
+ tokenX,
688
+ tokenY,
689
+ route.swapData,
690
+ this.context
691
+ );
692
+
693
+ if (typeof convertedResult === 'number' && convertedResult > 0) {
694
+ const updatedQuoteData = {
695
+ ...route.quoteData,
696
+ parameters: { ...params },
697
+ };
698
+
699
+ const updatedSwapData = {
700
+ ...route.swapData,
701
+ parameters: {
702
+ ...route.swapData.parameters,
703
+ amount:
704
+ params.amount ||
705
+ params.dx ||
706
+ params['amt-in'] ||
707
+ params['amt-in-max'] ||
708
+ params['y-amount'] ||
709
+ params['x-amount'] ||
710
+ params.dy,
711
+ dx:
712
+ params.amount ||
713
+ params.dx ||
714
+ params['amt-in'] ||
715
+ params['amt-in-max'] ||
716
+ params['y-amount'] ||
717
+ params['x-amount'] ||
718
+ params.dy,
719
+ 'amt-in':
720
+ params.amount ||
721
+ params.dx ||
722
+ params['amt-in'] ||
723
+ params['amt-in-max'] ||
724
+ params['y-amount'] ||
725
+ params['x-amount'] ||
726
+ params.dy,
727
+ 'amt-in-max':
728
+ params.amount ||
729
+ params.dx ||
730
+ params['amt-in'] ||
731
+ params['amt-in-max'] ||
732
+ params['y-amount'] ||
733
+ params['x-amount'] ||
734
+ params.dy,
735
+ 'y-amount':
736
+ params.amount ||
737
+ params.dx ||
738
+ params['amt-in'] ||
739
+ params['amt-in-max'] ||
740
+ params['y-amount'] ||
741
+ params['x-amount'] ||
742
+ params.dy,
743
+ 'x-amount':
744
+ params.amount ||
745
+ params.dx ||
746
+ params['amt-in'] ||
747
+ params['amt-in-max'] ||
748
+ params['y-amount'] ||
749
+ params['x-amount'] ||
750
+ params.dy,
751
+ 'min-received': rawResult,
752
+ 'min-dy': rawResult,
753
+ 'min-dz': rawResult,
754
+ 'min-dw': rawResult,
755
+ 'amt-out': rawResult,
756
+ 'amt-out-min': rawResult,
757
+ 'min-x-amount': rawResult,
758
+ 'min-dv': rawResult,
759
+ 'min-y-amount': rawResult,
760
+ 'min-dx': rawResult,
761
+ },
762
+ };
763
+
764
+ const quoteResult: RouteQuote = {
765
+ route: {
766
+ ...route,
767
+ quoteData: updatedQuoteData,
768
+ swapData: updatedSwapData,
769
+ },
770
+ quote: convertedResult,
771
+ params: params,
772
+ quoteData: updatedQuoteData,
773
+ swapData: updatedSwapData,
774
+ dexPath: route.dex_path,
775
+ tokenPath: route.token_path,
776
+ tokenXDecimals: tokenXDecimals,
777
+ tokenYDecimals: tokenYDecimals,
778
+ };
779
+
780
+ allRoutes.push(quoteResult);
781
+ } else {
782
+ throw new Error('Invalid quote result');
783
+ }
784
+ } catch (error) {
785
+ console.warn(
786
+ `Failed to get quote for route ${routeIndex + 1}:`,
787
+ route,
788
+ error
789
+ );
790
+ allRoutes.push({
791
+ route,
792
+ quote: null,
793
+ params: route.quoteData
794
+ ? { ...route.quoteData.parameters, amountInput }
795
+ : { amountInput },
796
+ quoteData: route.quoteData,
797
+ swapData: route.swapData,
798
+ dexPath: route.dex_path,
799
+ tokenPath: route.token_path,
800
+ tokenXDecimals: route.tokenXDecimals,
801
+ tokenYDecimals: route.tokenYDecimals,
802
+ error: (error as Error).message,
803
+ });
804
+ }
805
+ }
806
+
807
+ allRoutes.sort((a, b) => (b.quote || 0) - (a.quote || 0));
808
+ const result = {
809
+ bestRoute: allRoutes[0]?.quote !== null ? allRoutes[0] : null,
810
+ allRoutes,
811
+ inputData: { tokenX, tokenY, amountInput },
812
+ };
813
+
814
+ return result;
815
+ }
588
816
  public async getSwapParams(
589
817
  swapExecutionData: SwapExecutionData,
590
818
  senderAddress: string,
@@ -602,42 +830,42 @@ export class BitflowSDK {
602
830
  amount:
603
831
  route.swapData.parameters.amount ||
604
832
  amount ||
605
- route.swapData.parameters["amt-in"] ||
606
- route.swapData.parameters["amt-in-max"] ||
607
- route.swapData.parameters["y-amount"],
833
+ route.swapData.parameters['amt-in'] ||
834
+ route.swapData.parameters['amt-in-max'] ||
835
+ route.swapData.parameters['y-amount'],
608
836
  dx:
609
837
  route.swapData.parameters.dx ||
610
838
  amount ||
611
- route.swapData.parameters["amt-in"] ||
612
- route.swapData.parameters["amt-in-max"] ||
613
- route.swapData.parameters["y-amount"],
614
- "amt-in":
839
+ route.swapData.parameters['amt-in'] ||
840
+ route.swapData.parameters['amt-in-max'] ||
841
+ route.swapData.parameters['y-amount'],
842
+ 'amt-in':
615
843
  route.swapData.parameters.dx ||
616
844
  amount ||
617
- route.swapData.parameters["amt-in"] ||
618
- route.swapData.parameters["amt-in-max"] ||
619
- route.swapData.parameters["y-amount"] ||
845
+ route.swapData.parameters['amt-in'] ||
846
+ route.swapData.parameters['amt-in-max'] ||
847
+ route.swapData.parameters['y-amount'] ||
620
848
  route.swapData.parameters.dy,
621
- "amt-in-max":
849
+ 'amt-in-max':
622
850
  route.swapData.parameters.dx ||
623
851
  amount ||
624
- route.swapData.parameters["amt-in"] ||
625
- route.swapData.parameters["amt-in-max"] ||
626
- route.swapData.parameters["y-amount"] ||
852
+ route.swapData.parameters['amt-in'] ||
853
+ route.swapData.parameters['amt-in-max'] ||
854
+ route.swapData.parameters['y-amount'] ||
627
855
  route.swapData.parameters.dy,
628
- "y-amount":
856
+ 'y-amount':
629
857
  route.swapData.parameters.dx ||
630
858
  amount ||
631
- route.swapData.parameters["amt-in"] ||
632
- route.swapData.parameters["amt-in-max"] ||
633
- route.swapData.parameters["y-amount"] ||
859
+ route.swapData.parameters['amt-in'] ||
860
+ route.swapData.parameters['amt-in-max'] ||
861
+ route.swapData.parameters['y-amount'] ||
634
862
  route.swapData.parameters.dy,
635
863
  dy:
636
864
  route.swapData.parameters.dy ||
637
865
  amount ||
638
- route.swapData.parameters["amt-in"] ||
639
- route.swapData.parameters["amt-in-max"] ||
640
- route.swapData.parameters["y-amount"] ||
866
+ route.swapData.parameters['amt-in'] ||
867
+ route.swapData.parameters['amt-in-max'] ||
868
+ route.swapData.parameters['y-amount'] ||
641
869
  route.swapData.parameters.dy,
642
870
  },
643
871
  },
@@ -669,11 +897,11 @@ export class BitflowSDK {
669
897
  slippageTolerance
670
898
  );
671
899
 
672
- if (typeof window === "undefined") {
900
+ if (typeof window === 'undefined') {
673
901
  throw new Error(
674
- "executeSwap is only available in browser environments. " +
675
- "For Node.js environments, use getSwapParams to get the transaction parameters " +
676
- "and handle the transaction execution separately."
902
+ 'executeSwap is only available in browser environments. ' +
903
+ 'For Node.js environments, use getSwapParams to get the transaction parameters ' +
904
+ 'and handle the transaction execution separately.'
677
905
  );
678
906
  }
679
907
 
@@ -684,7 +912,7 @@ export class BitflowSDK {
684
912
  } else {
685
913
  const loadedProvider = await this.loadConnectDependencies();
686
914
  if (!loadedProvider) {
687
- throw new Error("Failed to initialize Stacks provider");
915
+ throw new Error('Failed to initialize Stacks provider');
688
916
  }
689
917
  provider = loadedProvider;
690
918
  }
@@ -700,14 +928,14 @@ export class BitflowSDK {
700
928
  } catch (error) {
701
929
  if (
702
930
  error instanceof Error &&
703
- error.message.includes("only available in browser environments")
931
+ error.message.includes('only available in browser environments')
704
932
  ) {
705
933
  throw error;
706
934
  }
707
- console.error("Error executing swap:", error);
935
+ console.error('Error executing swap:', error);
708
936
  throw new Error(
709
937
  `Failed to execute swap: ${
710
- error instanceof Error ? error.message : "Unknown error"
938
+ error instanceof Error ? error.message : 'Unknown error'
711
939
  }`
712
940
  );
713
941
  }
@@ -731,7 +959,7 @@ export class BitflowSDK {
731
959
  try {
732
960
  return await getOrCreateKeeperContractAPI(params);
733
961
  } catch (error) {
734
- console.error("Error in BitflowSDK.getOrCreateKeeperContract:", error);
962
+ console.error('Error in BitflowSDK.getOrCreateKeeperContract:', error);
735
963
  throw error;
736
964
  }
737
965
  }
@@ -740,7 +968,7 @@ export class BitflowSDK {
740
968
  try {
741
969
  return await getOrderAPI(orderId);
742
970
  } catch (error) {
743
- console.error("Error in BitflowSDK.getOrder:", error);
971
+ console.error('Error in BitflowSDK.getOrder:', error);
744
972
  throw error;
745
973
  }
746
974
  }
@@ -749,7 +977,7 @@ export class BitflowSDK {
749
977
  try {
750
978
  return await getUserAPI(stacksAddress);
751
979
  } catch (error) {
752
- console.error("Error in BitflowSDK.getUser:", error);
980
+ console.error('Error in BitflowSDK.getUser:', error);
753
981
  throw error;
754
982
  }
755
983
  }
@@ -760,7 +988,7 @@ export class BitflowSDK {
760
988
  try {
761
989
  return await createOrderAPI(params);
762
990
  } catch (error) {
763
- console.error("Error in BitflowSDK.createOrder:", error);
991
+ console.error('Error in BitflowSDK.createOrder:', error);
764
992
  throw error;
765
993
  }
766
994
  }
@@ -769,28 +997,11 @@ export class BitflowSDK {
769
997
  try {
770
998
  return await getQuoteAPI(params);
771
999
  } catch (error) {
772
- console.error("Error in BitflowSDK.getQuote:", error);
1000
+ console.error('Error in BitflowSDK.getQuote:', error);
773
1001
  throw error;
774
1002
  }
775
1003
  }
776
1004
 
777
- private mapDexPathToActionTrait(dexPath: string[]): string {
778
- const isXYK = dexPath.some((d) => d.toLowerCase().includes("xyk"));
779
- const isStable = dexPath.some((d) => d.toLowerCase().includes("stable"));
780
-
781
- if (isXYK && !isStable) {
782
- return "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.keeper-action-1-v-1-1";
783
- }
784
- if (isXYK && isStable) {
785
- return "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.keeper-action-2-v-1-1";
786
- }
787
- if (!isXYK && isStable) {
788
- return "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.keeper-action-3-v-1-1";
789
- }
790
-
791
- throw new Error(`Unsupported DEX path: ${dexPath.join(", ")}`);
792
- }
793
-
794
1005
  private async transformRouteToActionArgs(
795
1006
  route: RouteQuote
796
1007
  ): Promise<ActionFunctionArgs> {
@@ -804,89 +1015,136 @@ export class BitflowSDK {
804
1015
  const swapData = route.swapData;
805
1016
  if (!swapData || !swapData.parameters) {
806
1017
  throw new Error(
807
- "Invalid route data - missing swapData or swapData.parameters"
1018
+ 'Invalid route data - missing swapData or swapData.parameters'
808
1019
  );
809
1020
  }
810
1021
 
811
- const availableTokens = await this.getAvailableTokens();
812
- const tokenPath = route.tokenPath;
813
- const expandedTokenPath: string[] = [];
1022
+ try {
1023
+ const availableTokens = await this.getAvailableTokens();
1024
+ const tokenPath = route.tokenPath;
1025
+ const expandedTokenPath: string[] = [];
814
1026
 
815
- for (let i = 0; i < tokenPath.length - 1; i++) {
816
- expandedTokenPath.push(tokenPath[i]);
817
- if (i > 0 && i < tokenPath.length - 1) {
1027
+ // Expand token path
1028
+ for (let i = 0; i < tokenPath.length - 1; i++) {
818
1029
  expandedTokenPath.push(tokenPath[i]);
819
- }
820
- }
821
- expandedTokenPath.push(tokenPath[tokenPath.length - 1]);
822
-
823
- const tokenList: Record<string, string> = {};
824
- expandedTokenPath.forEach((tokenId, index) => {
825
- let contractIdentifier: string;
826
- if (tokenId === "token-stx") {
827
- contractIdentifier =
828
- "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.token-stx-v-1-2";
829
- } else {
830
- const token = availableTokens.find((t) => t.tokenId === tokenId);
831
- if (!token || !token.tokenContract) {
832
- throw new Error(
833
- `Could not find contract identifier for token ${tokenId}`
834
- );
1030
+ if (i > 0 && i < tokenPath.length - 1) {
1031
+ expandedTokenPath.push(tokenPath[i]);
835
1032
  }
836
- contractIdentifier = token.tokenContract;
837
1033
  }
838
- const key = String.fromCharCode(97 + index); // 97 = 'a'
839
- tokenList[key] = contractIdentifier;
840
- });
1034
+ expandedTokenPath.push(tokenPath[tokenPath.length - 1]);
1035
+
1036
+ // Map tokens to contract identifiers
1037
+ const tokenList: Record<string, string> = {};
1038
+ for (let index = 0; index < expandedTokenPath.length; index++) {
1039
+ const tokenId = expandedTokenPath[index];
1040
+ let contractIdentifier: string;
841
1041
 
842
- actionFunctionArgs.tokenList = tokenList;
1042
+ if (tokenId === 'token-stx') {
1043
+ contractIdentifier =
1044
+ 'SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.token-stx-v-1-2';
1045
+ } else {
1046
+ const token = availableTokens.find((t) => t.tokenId === tokenId);
1047
+ if (!token || !token.tokenContract) {
1048
+ throw new Error(
1049
+ `Could not find contract identifier for token ${tokenId}`
1050
+ );
1051
+ }
1052
+ contractIdentifier = token.tokenContract;
1053
+ }
843
1054
 
844
- const transformPoolList = (pools: any): Record<string, string> => {
845
- if (typeof pools === "string") {
846
- return { a: pools };
1055
+ const key = String.fromCharCode(97 + index); // 97 = 'a'
1056
+ tokenList[key] = contractIdentifier;
847
1057
  }
848
- if (Array.isArray(pools)) {
849
- const poolObject: Record<string, string> = {};
850
- const letters = "abcdefghijklmnopqrstuvwxyz";
851
- pools.forEach((pool, index) => {
852
- poolObject[letters[index]] = pool;
853
- });
854
- return poolObject;
1058
+
1059
+ actionFunctionArgs.tokenList = tokenList;
1060
+
1061
+ // Determine if this is a stableswap or XYK route
1062
+ const dexPath = route.dexPath;
1063
+ const isStableswapRoute = dexPath.some((path) =>
1064
+ path.toLowerCase().includes('stable')
1065
+ );
1066
+
1067
+ // Transform pool lists
1068
+ const transformPoolList = (pools: any): Record<string, string> => {
1069
+ if (typeof pools === 'string') {
1070
+ return { a: pools };
1071
+ }
1072
+ if (Array.isArray(pools)) {
1073
+ const poolObject: Record<string, string> = {};
1074
+ const letters = 'abcdefghijklmnopqrstuvwxyz';
1075
+ pools.forEach((pool, index) => {
1076
+ poolObject[letters[index]] = pool;
1077
+ });
1078
+ return poolObject;
1079
+ }
1080
+ if (typeof pools === 'object' && pools !== null) {
1081
+ return pools;
1082
+ }
1083
+ return {};
1084
+ };
1085
+
1086
+ // Handle pools based on whether they're stableswap or XYK
1087
+ if (swapData.parameters['pool-trait']) {
1088
+ const poolIdentifier = swapData.parameters['pool-trait'];
1089
+ const transformedPool = transformPoolList(poolIdentifier);
1090
+
1091
+ // Check if the pool name contains 'stableswap'
1092
+ if (
1093
+ isStableswapRoute ||
1094
+ (typeof poolIdentifier === 'string' &&
1095
+ poolIdentifier.toLowerCase().includes('stableswap'))
1096
+ ) {
1097
+ actionFunctionArgs.stableswapPoolList = transformedPool;
1098
+ } else {
1099
+ actionFunctionArgs.xykPoolList = transformedPool;
1100
+ }
1101
+ } else {
1102
+ // Handle specific pool types
1103
+ if (swapData.parameters['xyk-pools']) {
1104
+ actionFunctionArgs.xykPoolList = transformPoolList(
1105
+ swapData.parameters['xyk-pools']
1106
+ );
1107
+ }
1108
+
1109
+ if (swapData.parameters['stableswap-pools']) {
1110
+ actionFunctionArgs.stableswapPoolList = transformPoolList(
1111
+ swapData.parameters['stableswap-pools']
1112
+ );
1113
+ }
855
1114
  }
856
- if (typeof pools === "object" && pools !== null) {
857
- return pools;
1115
+
1116
+ if ('swaps-reversed' in swapData.parameters) {
1117
+ actionFunctionArgs.boolList = {
1118
+ a: swapData.parameters['swaps-reversed'].toString(),
1119
+ };
1120
+ } else {
1121
+ delete actionFunctionArgs.boolList;
858
1122
  }
859
- return {};
860
- };
861
1123
 
862
- if (swapData.parameters["xyk-pools"]) {
863
- actionFunctionArgs.xykPoolList = transformPoolList(
864
- swapData.parameters["xyk-pools"]
865
- );
866
- } else if (swapData.parameters["pool-trait"]) {
867
- actionFunctionArgs.xykPoolList = transformPoolList(
868
- swapData.parameters["pool-trait"]
869
- );
870
- }
1124
+ const trait = this.mapDexPathToActionTrait(dexPath);
1125
+ actionFunctionArgs.actionTrait = trait;
871
1126
 
872
- if (swapData.parameters["stableswap-pools"]) {
873
- actionFunctionArgs.stableswapPoolList =
874
- swapData.parameters["stableswap-pools"];
1127
+ return actionFunctionArgs;
1128
+ } catch (error) {
1129
+ throw error;
875
1130
  }
1131
+ }
876
1132
 
877
- if ("swaps-reversed" in swapData.parameters) {
878
- actionFunctionArgs.boolList = {
879
- a: swapData.parameters["swaps-reversed"].toString(),
880
- };
881
- } else {
882
- delete actionFunctionArgs.boolList;
883
- }
1133
+ private mapDexPathToActionTrait(dexPath: string[]): string {
1134
+ const isXYK = dexPath.some((d) => d.toLowerCase().includes('xyk'));
1135
+ const isStable = dexPath.some((d) => d.toLowerCase().includes('stable'));
884
1136
 
885
- const dexPath = route.dexPath;
886
- const trait = this.mapDexPathToActionTrait(dexPath);
887
- actionFunctionArgs.actionTrait = trait;
1137
+ if (isXYK && !isStable) {
1138
+ return 'SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.keeper-action-1-v-1-1';
1139
+ }
1140
+ if (isXYK && isStable) {
1141
+ return 'SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.keeper-action-2-v-1-1';
1142
+ }
1143
+ if (!isXYK && isStable) {
1144
+ return 'SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.keeper-action-3-v-1-1';
1145
+ }
888
1146
 
889
- return actionFunctionArgs;
1147
+ throw new Error(`Unsupported DEX path: ${dexPath.join(', ')}`);
890
1148
  }
891
1149
 
892
1150
  public async getKeeperAggregatorRouteData(
@@ -894,28 +1152,33 @@ export class BitflowSDK {
894
1152
  tokenY: string,
895
1153
  amountX: number
896
1154
  ): Promise<ActionFunctionArgs> {
897
- const quoteResult = await this.getKeeperQuoteForRoute(
898
- tokenX,
899
- tokenY,
900
- amountX
901
- );
902
-
903
- if (
904
- !quoteResult ||
905
- !quoteResult.allRoutes ||
906
- quoteResult.allRoutes.length === 0
907
- ) {
908
- throw new Error("No routes found");
909
- }
1155
+ try {
1156
+ const quoteResult = await this.getKeeperQuoteForRouteWithoutScaling(
1157
+ tokenX,
1158
+ tokenY,
1159
+ amountX
1160
+ );
910
1161
 
911
- const { bestRoute } = quoteResult;
912
- if (!bestRoute) {
913
- throw new Error("No best route found for keeper-compatible DEX paths");
914
- }
1162
+ if (
1163
+ !quoteResult ||
1164
+ !quoteResult.allRoutes ||
1165
+ quoteResult.allRoutes.length === 0
1166
+ ) {
1167
+ throw new Error('No routes found');
1168
+ }
915
1169
 
916
- const actionFunctionArgs = this.transformRouteToActionArgs(bestRoute);
1170
+ const { bestRoute } = quoteResult;
1171
+ if (!bestRoute) {
1172
+ throw new Error('No best route found for keeper-compatible DEX paths');
1173
+ }
917
1174
 
918
- return actionFunctionArgs;
1175
+ const actionFunctionArgs = await this.transformRouteToActionArgs(
1176
+ bestRoute
1177
+ );
1178
+ return actionFunctionArgs;
1179
+ } catch (error) {
1180
+ throw error;
1181
+ }
919
1182
  }
920
1183
 
921
1184
  public async createGroupOrder(
@@ -924,7 +1187,7 @@ export class BitflowSDK {
924
1187
  try {
925
1188
  return await createGroupOrderAPI(params);
926
1189
  } catch (error) {
927
- console.error("Error in BitflowSDK.createGroupOrder:", error);
1190
+ console.error('Error in BitflowSDK.createGroupOrder:', error);
928
1191
  throw error;
929
1192
  }
930
1193
  }
@@ -936,7 +1199,7 @@ export class BitflowSDK {
936
1199
  try {
937
1200
  return await getGroupOrderAPI(groupId, includeOrders);
938
1201
  } catch (error) {
939
- console.error("Error in BitflowSDK.getGroupOrder:", error);
1202
+ console.error('Error in BitflowSDK.getGroupOrder:', error);
940
1203
  throw error;
941
1204
  }
942
1205
  }
@@ -945,7 +1208,7 @@ export class BitflowSDK {
945
1208
  try {
946
1209
  return await cancelOrderAPI(orderId);
947
1210
  } catch (error) {
948
- console.error("Error in BitflowSDK.cancelOrder:", error);
1211
+ console.error('Error in BitflowSDK.cancelOrder:', error);
949
1212
  throw error;
950
1213
  }
951
1214
  }
@@ -956,7 +1219,7 @@ export class BitflowSDK {
956
1219
  try {
957
1220
  return await cancelGroupOrderAPI(groupId);
958
1221
  } catch (error) {
959
- console.error("Error in BitflowSDK.cancelGroupOrder:", error);
1222
+ console.error('Error in BitflowSDK.cancelGroupOrder:', error);
960
1223
  throw error;
961
1224
  }
962
1225
  }