@rabbitio/ui-kit 1.0.0-beta.42 → 1.0.0-beta.45

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 (67) hide show
  1. package/.gitlab-ci.yml +29 -0
  2. package/.husky/commit-msg +8 -0
  3. package/.husky/pre-push +1 -0
  4. package/README.md +13 -4
  5. package/dist/index.cjs +1545 -148
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.css +23630 -0
  8. package/dist/index.css.map +1 -1
  9. package/dist/index.modern.js +1318 -103
  10. package/dist/index.modern.js.map +1 -1
  11. package/dist/index.module.js +1534 -149
  12. package/dist/index.module.js.map +1 -1
  13. package/dist/index.umd.js +1544 -152
  14. package/dist/index.umd.js.map +1 -1
  15. package/package.json +16 -3
  16. package/src/assets/image/icons/arrow-tosca.svg +3 -0
  17. package/src/assets/image/icons/arrow-white.svg +14 -0
  18. package/src/assets/image/icons/failed-validation-icon.svg +15 -0
  19. package/src/assets/image/icons/successful-validation-icon.svg +10 -0
  20. package/src/common/amountUtils.js +4 -2
  21. package/src/common/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js +14 -0
  22. package/src/common/utils/cache.js +4 -4
  23. package/src/components/atoms/BackgroundTitle/BackgroundTitle.jsx +44 -0
  24. package/src/components/atoms/BackgroundTitle/background-title.module.scss +52 -0
  25. package/src/components/atoms/Validation/Validation.jsx +130 -0
  26. package/src/components/atoms/Validation/validation.module.scss +15 -0
  27. package/src/components/atoms/buttons/Close/Close.jsx +64 -0
  28. package/src/components/atoms/buttons/Close/close.module.scss +75 -0
  29. package/src/components/atoms/buttons/LinkButton/LinkButton.jsx +121 -0
  30. package/src/components/atoms/buttons/LinkButton/link-button.module.scss +45 -0
  31. package/src/components/organisms/Dialog/Dialog.jsx +515 -0
  32. package/src/components/organisms/Dialog/DialogButtons/DialogButtons.jsx +122 -0
  33. package/src/components/organisms/Dialog/DialogButtons/dialog-buttons.module.scss +25 -0
  34. package/src/components/organisms/Dialog/DialogStep/DialogStep.jsx +664 -0
  35. package/src/components/organisms/Dialog/DialogStep/dialog-step.module.scss +362 -0
  36. package/src/components/organisms/Dialog/dialog.module.scss +223 -0
  37. package/src/components/tests/utils/inputValueProviders/provideFormatOfFloatValueByInputString.test.js +139 -0
  38. package/src/components/tests/utils/urlQueryUtils/getQueryParameterValues.test.js +71 -0
  39. package/src/components/tests/utils/urlQueryUtils/saveQueryParameterAndValues.test.js +144 -0
  40. package/src/components/utils/inputValueProviders.js +58 -0
  41. package/src/constants/organisms/dialog/DialogStep/dialogStep.js +1 -0
  42. package/src/constants/organisms/dialog/dialog.js +29 -0
  43. package/src/index.js +11 -0
  44. package/src/robustExteranlApiCallerService/robustExternalAPICallerService.js +3 -1
  45. package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/_performCallAttempt.test.js +787 -0
  46. package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/callExternalAPI.test.js +745 -0
  47. package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/constructor.test.js +31 -0
  48. package/src/swaps-lib/external-apis/swapProvider.js +17 -4
  49. package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +91 -30
  50. package/src/swaps-lib/models/baseSwapCreationInfo.js +4 -1
  51. package/src/swaps-lib/models/existingSwap.js +3 -0
  52. package/src/swaps-lib/models/existingSwapWithFiatData.js +4 -0
  53. package/src/swaps-lib/services/publicSwapService.js +32 -4
  54. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +506 -0
  55. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/createSwap.test.js +1311 -0
  56. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getAllSupportedCurrencies.test.js +76 -0
  57. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getDepositCurrencies.test.js +82 -0
  58. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getSwapInfo.test.js +1892 -0
  59. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getWithdrawalCurrencies.test.js +111 -0
  60. package/src/swaps-lib/test/utils/swapUtils/safeHandleRequestsLimitExceeding.test.js +88 -0
  61. package/stories/stubs/exampleContent.jsx +20 -0
  62. package/styles/fonts/NunitoSans-Bold.ttf +0 -0
  63. package/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
  64. package/styles/fonts/NunitoSans-Light.ttf +0 -0
  65. package/styles/fonts/NunitoSans-Regular.ttf +0 -0
  66. package/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
  67. package/styles/index.scss +14 -13
@@ -0,0 +1,1892 @@
1
+ import sinon from "sinon";
2
+ import axios from "axios";
3
+ import should from "should";
4
+
5
+ import { beforeEach, afterEach, describe, it } from "vitest";
6
+
7
+ import { SwapProvider } from "../../../external-apis/swapProvider.js";
8
+ import { SwapspaceSwapProvider } from "../../../external-apis/swapspaceSwapProvider.js";
9
+ import { Cache } from "../../../../common/utils/cache.js";
10
+ import { AmountUtils } from "../../../../common/amountUtils.js";
11
+ import { Coin } from "../../../../common/models/coin.js";
12
+ import { Blockchain } from "../../../../common/models/blockchain.js";
13
+
14
+ describe("swapspaceSwapProvider", function () {
15
+ describe("getSwapInfo", function () {
16
+ const BTC = new Coin(
17
+ "Bitcoin",
18
+ "BTC",
19
+ "BTC",
20
+ 8,
21
+ null,
22
+ "sat",
23
+ null,
24
+ null,
25
+ 1,
26
+ null,
27
+ [],
28
+ null,
29
+ new Blockchain("Bitcoin")
30
+ );
31
+ const ETH = new Coin(
32
+ "Ethereum",
33
+ "ETH",
34
+ "ETH",
35
+ 18,
36
+ null,
37
+ "wei",
38
+ null,
39
+ null,
40
+ 1,
41
+ null,
42
+ [],
43
+ null,
44
+ new Blockchain("Ethereum")
45
+ );
46
+ const TRX = new Coin(
47
+ "Tron",
48
+ "TRX",
49
+ "TRX",
50
+ 18,
51
+ null,
52
+ "sun",
53
+ null,
54
+ null,
55
+ 1,
56
+ null,
57
+ [],
58
+ null,
59
+ new Blockchain("Tron")
60
+ );
61
+ const USDCTRC20 = new Coin(
62
+ "USDCTRC20",
63
+ "USDCTRC20",
64
+ "USDC",
65
+ 6,
66
+ null,
67
+ "millicents",
68
+ null,
69
+ null,
70
+ 1,
71
+ null,
72
+ [],
73
+ null,
74
+ new Blockchain("Tron")
75
+ );
76
+ const USDTERC20 = new Coin(
77
+ "USDTERC20",
78
+ "USDTERC20",
79
+ "USDT",
80
+ 6,
81
+ null,
82
+ "millicents",
83
+ null,
84
+ null,
85
+ 1,
86
+ null,
87
+ [],
88
+ null,
89
+ new Blockchain("Ethereum")
90
+ );
91
+
92
+ let swapspaceSwapProvider;
93
+ let axiosGetStub;
94
+ let trimCryptoAmountByCoinStub;
95
+
96
+ beforeEach(() => {
97
+ swapspaceSwapProvider = new SwapspaceSwapProvider("", new Cache());
98
+
99
+ axiosGetStub = sinon.stub(axios, "get");
100
+
101
+ trimCryptoAmountByCoinStub = sinon.stub(AmountUtils, "trim");
102
+ trimCryptoAmountByCoinStub.callsFake((amount) =>
103
+ amount?.toString()
104
+ );
105
+ });
106
+
107
+ afterEach(() => {
108
+ sinon.restore();
109
+ });
110
+
111
+ it("should return a result of correct format when available exchanges are present", async () => {
112
+ swapspaceSwapProvider._supportedCoins = [
113
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
114
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
115
+ ];
116
+ const mockData = [
117
+ {
118
+ exists: true,
119
+ fixed: false,
120
+ toAmount: 2,
121
+ fromAmount: 1,
122
+ duration: "10-20",
123
+ max: 5,
124
+ min: 0.1,
125
+ },
126
+ ];
127
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
128
+
129
+ const result = await swapspaceSwapProvider.getSwapInfo(
130
+ BTC,
131
+ ETH,
132
+ "1"
133
+ );
134
+
135
+ result.result.should.be.true();
136
+ result.min.should.be.String();
137
+ result.max.should.be.String();
138
+ result.smallestMin.should.be.String();
139
+ result.greatestMax.should.be.String();
140
+ result.rate.should.be.String();
141
+ result.durationMinutesRange.should.be.String();
142
+ result.rawSwapData.should.be.Object();
143
+ result.fixed.should.be.Boolean();
144
+ });
145
+
146
+ it("should return a result of correct format when there are no available exchange options but some not relevant options have min/max amount", async () => {
147
+ swapspaceSwapProvider._supportedCoins = [
148
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
149
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
150
+ ];
151
+ axiosGetStub.resolves({
152
+ data: [
153
+ {
154
+ exists: true,
155
+ fixed: false,
156
+ toAmount: 0,
157
+ fromAmount: 1,
158
+ duration: "10-20",
159
+ max: 5,
160
+ min: 0.1,
161
+ },
162
+ ],
163
+ });
164
+
165
+ const result = await swapspaceSwapProvider.getSwapInfo(
166
+ BTC,
167
+ ETH,
168
+ "0.01"
169
+ );
170
+
171
+ result.result.should.be.false();
172
+ (
173
+ Object.values(SwapProvider.NO_SWAPS_REASONS).find(
174
+ (v) => result.reason === v
175
+ ) == null
176
+ ).should.be.false();
177
+ result.smallestMin.should.be.String();
178
+ result.greatestMax.should.be.String();
179
+ });
180
+
181
+ it("should use the exchange with the highest rate", async () => {
182
+ swapspaceSwapProvider._supportedCoins = [
183
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
184
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
185
+ ];
186
+ const mockData = [
187
+ {
188
+ exists: true,
189
+ fixed: false,
190
+ toAmount: 2,
191
+ fromAmount: 1,
192
+ duration: "10-20",
193
+ max: 5,
194
+ min: 0.1,
195
+ },
196
+ {
197
+ exists: true,
198
+ fixed: false,
199
+ toAmount: 3,
200
+ fromAmount: 1,
201
+ duration: "10-20",
202
+ max: 5,
203
+ min: 0.1,
204
+ },
205
+ ];
206
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
207
+
208
+ const result = await swapspaceSwapProvider.getSwapInfo(
209
+ BTC,
210
+ ETH,
211
+ "1"
212
+ );
213
+
214
+ result.rawSwapData.should.be.deepEqual(mockData[1]);
215
+ });
216
+
217
+ it("should return result with proper rate calculation if the selected exchange has toAmount, fromAmount and the coin usd rate is successfully retrieved", async () => {
218
+ swapspaceSwapProvider._supportedCoins = [
219
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
220
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
221
+ ];
222
+ const mockData = [
223
+ {
224
+ exists: true,
225
+ fixed: false,
226
+ toAmount: 3,
227
+ fromAmount: 2,
228
+ duration: "10-20",
229
+ max: 5,
230
+ min: 0.1,
231
+ },
232
+ ];
233
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
234
+
235
+ const result = await swapspaceSwapProvider.getSwapInfo(
236
+ BTC,
237
+ ETH,
238
+ "1"
239
+ );
240
+
241
+ result.rate.should.be.equal("1.5"); // because 3 divided by 2 is 1.5
242
+ });
243
+
244
+ it("should use the first best exchange option when multiple exchanges have the same toAmount", async () => {
245
+ swapspaceSwapProvider._supportedCoins = [
246
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
247
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
248
+ ];
249
+ const mockData = [
250
+ {
251
+ exists: true,
252
+ fixed: false,
253
+ toAmount: 3,
254
+ fromAmount: 1,
255
+ duration: "11-21",
256
+ max: 5,
257
+ min: 0.1,
258
+ },
259
+ {
260
+ exists: true,
261
+ fixed: false,
262
+ toAmount: 3,
263
+ fromAmount: 1,
264
+ duration: "10-20",
265
+ max: 6,
266
+ min: 0.2,
267
+ },
268
+ ];
269
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
270
+
271
+ const result = await swapspaceSwapProvider.getSwapInfo(
272
+ BTC,
273
+ ETH,
274
+ "1"
275
+ );
276
+
277
+ result.durationMinutesRange.should.be.equal("11-21"); // Using the first one by order
278
+ });
279
+
280
+ it("should return a rawSwapData object for available exchanges", async () => {
281
+ swapspaceSwapProvider._supportedCoins = [
282
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
283
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
284
+ ];
285
+ const mockData = [
286
+ {
287
+ exists: true,
288
+ fixed: false,
289
+ toAmount: 2,
290
+ fromAmount: 1,
291
+ duration: "10-20",
292
+ max: 5,
293
+ min: 0.1,
294
+ },
295
+ ];
296
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
297
+
298
+ const result = await swapspaceSwapProvider.getSwapInfo(
299
+ BTC,
300
+ ETH,
301
+ "1"
302
+ );
303
+
304
+ result.rawSwapData.should.be.deepEqual(mockData[0]);
305
+ });
306
+
307
+ it("should handle REQUESTS_LIMIT_EXCEEDED when axios returns a 429", async () => {
308
+ swapspaceSwapProvider._supportedCoins = [
309
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
310
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
311
+ ];
312
+ axiosGetStub.throws({ response: { status: 429 } });
313
+
314
+ const result = await swapspaceSwapProvider.getSwapInfo(
315
+ BTC,
316
+ ETH,
317
+ "1"
318
+ );
319
+
320
+ result.reason.should.be.equal(
321
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
322
+ );
323
+ });
324
+
325
+ it("should return TOO_LOW when amount is below the smallest minimum and there are no available exchange option", async () => {
326
+ swapspaceSwapProvider._supportedCoins = [
327
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
328
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
329
+ ];
330
+ const mockData = [
331
+ {
332
+ exists: true,
333
+ fixed: false,
334
+ toAmount: 0,
335
+ fromAmount: 1,
336
+ duration: "10-20",
337
+ max: 5,
338
+ min: 2,
339
+ },
340
+ {
341
+ exists: true,
342
+ fixed: false,
343
+ toAmount: 0,
344
+ fromAmount: 1,
345
+ duration: "10-30",
346
+ max: 50,
347
+ min: 3,
348
+ },
349
+ ];
350
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
351
+
352
+ const result = await swapspaceSwapProvider.getSwapInfo(
353
+ BTC,
354
+ ETH,
355
+ "1"
356
+ );
357
+
358
+ result.result.should.be.false();
359
+ result.reason.should.be.equal(
360
+ SwapProvider.NO_SWAPS_REASONS.TOO_LOW
361
+ );
362
+ });
363
+
364
+ it("should return TOO_HIGH when amount is above the greatest max and there are no available exchange option", async () => {
365
+ swapspaceSwapProvider._supportedCoins = [
366
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
367
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
368
+ ];
369
+ const mockData = [
370
+ {
371
+ exists: true,
372
+ fixed: false,
373
+ toAmount: 0,
374
+ fromAmount: 1,
375
+ duration: "10-20",
376
+ max: 4,
377
+ min: 0.1,
378
+ },
379
+ {
380
+ exists: true,
381
+ fixed: false,
382
+ toAmount: 0,
383
+ fromAmount: 1,
384
+ duration: "10-20",
385
+ max: 1.1,
386
+ min: 0.4,
387
+ },
388
+ ];
389
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
390
+
391
+ const result = await swapspaceSwapProvider.getSwapInfo(
392
+ BTC,
393
+ ETH,
394
+ "10"
395
+ );
396
+
397
+ result.result.should.be.false();
398
+ result.reason.should.be.equal(
399
+ SwapProvider.NO_SWAPS_REASONS.TOO_HIGH
400
+ );
401
+ });
402
+
403
+ it("should return NOT_SUPPORTED when no exchanges support the pair", async () => {
404
+ swapspaceSwapProvider._supportedCoins = [
405
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
406
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
407
+ ];
408
+ axiosGetStub.returns(Promise.resolve({ data: [] }));
409
+
410
+ const result = await swapspaceSwapProvider.getSwapInfo(
411
+ BTC,
412
+ ETH,
413
+ "1"
414
+ );
415
+
416
+ result.result.should.be.false();
417
+ result.reason.should.be.equal(
418
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
419
+ );
420
+ });
421
+
422
+ it("should return NOT_SUPPORTED when deposit is false for from currency", async () => {
423
+ swapspaceSwapProvider._supportedCoins = [
424
+ { coin: BTC, code: "btc", network: "btc", deposit: false },
425
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
426
+ ];
427
+ axiosGetStub.returns(Promise.resolve({ data: [] }));
428
+
429
+ const result = await swapspaceSwapProvider.getSwapInfo(
430
+ BTC,
431
+ ETH,
432
+ "1"
433
+ );
434
+
435
+ result.result.should.be.false();
436
+ result.reason.should.be.equal(
437
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
438
+ );
439
+ });
440
+
441
+ it("should return NOT_SUPPORTED when withdrawal is false for to currency", async () => {
442
+ swapspaceSwapProvider._supportedCoins = [
443
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
444
+ { coin: ETH, code: "eth", network: "eth", withdrawal: false },
445
+ ];
446
+ axiosGetStub.returns(Promise.resolve({ data: [] }));
447
+
448
+ const result = await swapspaceSwapProvider.getSwapInfo(
449
+ BTC,
450
+ ETH,
451
+ "1"
452
+ );
453
+
454
+ result.result.should.be.false();
455
+ result.reason.should.be.equal(
456
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
457
+ );
458
+ });
459
+
460
+ it("should return NO_FIXED_BUT_HAVE_FLOATING when fixed passed is true and there is no fixed option but there is floating option", async () => {
461
+ swapspaceSwapProvider._supportedCoins = [
462
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
463
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
464
+ ];
465
+ axiosGetStub.returns(
466
+ Promise.resolve({
467
+ data: [
468
+ {
469
+ exists: true,
470
+ fixed: false,
471
+ toAmount: 10,
472
+ fromAmount: 1,
473
+ duration: "10-20",
474
+ max: 5,
475
+ min: 0.1,
476
+ },
477
+ ],
478
+ })
479
+ );
480
+
481
+ const result = await swapspaceSwapProvider.getSwapInfo(
482
+ BTC,
483
+ ETH,
484
+ "1",
485
+ true
486
+ );
487
+
488
+ result.result.should.be.false();
489
+ result.reason.should.be.equal(
490
+ SwapProvider.NO_SWAPS_REASONS.NO_FIXED_BUT_HAVE_FLOATING
491
+ );
492
+ });
493
+
494
+ it("should return NO_FLOATING_BUT_HAVE_FIXED when fixed passed is false and there is no floating option but there is fixed option", async () => {
495
+ swapspaceSwapProvider._supportedCoins = [
496
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
497
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
498
+ ];
499
+ axiosGetStub.returns(
500
+ Promise.resolve({
501
+ data: [
502
+ {
503
+ exists: true,
504
+ fixed: true,
505
+ toAmount: 10,
506
+ fromAmount: 1,
507
+ duration: "10-20",
508
+ max: 5,
509
+ min: 0.1,
510
+ },
511
+ ],
512
+ })
513
+ );
514
+
515
+ const result = await swapspaceSwapProvider.getSwapInfo(
516
+ BTC,
517
+ ETH,
518
+ "1",
519
+ false
520
+ );
521
+
522
+ result.result.should.be.false();
523
+ result.reason.should.be.equal(
524
+ SwapProvider.NO_SWAPS_REASONS.NO_FLOATING_BUT_HAVE_FIXED
525
+ );
526
+ });
527
+
528
+ it("should return best option across both fixed and floating when fixed passed is null", async () => {
529
+ swapspaceSwapProvider._supportedCoins = [
530
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
531
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
532
+ ];
533
+ const opts = [
534
+ {
535
+ exists: true,
536
+ fixed: false,
537
+ toAmount: 10,
538
+ fromAmount: 1,
539
+ duration: "10-20",
540
+ max: 5,
541
+ min: 0.1,
542
+ },
543
+ {
544
+ exists: true,
545
+ fixed: true,
546
+ toAmount: 11,
547
+ fromAmount: 1,
548
+ duration: "2",
549
+ max: 6,
550
+ min: 0.3,
551
+ },
552
+ ];
553
+ axiosGetStub.returns(
554
+ Promise.resolve({
555
+ data: opts,
556
+ })
557
+ );
558
+
559
+ const result = await swapspaceSwapProvider.getSwapInfo(
560
+ BTC,
561
+ ETH,
562
+ "1",
563
+ null
564
+ );
565
+
566
+ result.result.should.be.true();
567
+ result.rawSwapData.should.be.deepEqual(opts[1]);
568
+ });
569
+
570
+ it("should correctly handle when there are available exchange options and no smallest min", async () => {
571
+ swapspaceSwapProvider._supportedCoins = [
572
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
573
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
574
+ ];
575
+ axiosGetStub.resolves({
576
+ data: [
577
+ {
578
+ exists: true,
579
+ fixed: false,
580
+ toAmount: 10,
581
+ fromAmount: 1,
582
+ duration: "10-20",
583
+ max: 5,
584
+ min: "a",
585
+ },
586
+ ],
587
+ });
588
+
589
+ const result = await swapspaceSwapProvider.getSwapInfo(
590
+ BTC,
591
+ ETH,
592
+ "6"
593
+ );
594
+
595
+ result.result.should.be.true();
596
+ (result.smallestMin === null).should.be.true();
597
+ });
598
+
599
+ it("should correctly handle when there are available exchange options and no greatest max", async () => {
600
+ swapspaceSwapProvider._supportedCoins = [
601
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
602
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
603
+ ];
604
+ axiosGetStub.resolves({
605
+ data: [
606
+ {
607
+ exists: true,
608
+ fixed: false,
609
+ toAmount: 10,
610
+ fromAmount: 1,
611
+ duration: "10-20",
612
+ max: "f",
613
+ min: 0.1,
614
+ },
615
+ ],
616
+ });
617
+
618
+ const result = await swapspaceSwapProvider.getSwapInfo(
619
+ BTC,
620
+ ETH,
621
+ "0.01"
622
+ );
623
+
624
+ result.result.should.be.true();
625
+ (result.greatestMax === null).should.be.true();
626
+ });
627
+
628
+ it("should increase the min with coinAmountForMinMaxSafety", async () => {
629
+ swapspaceSwapProvider._supportedCoins = [
630
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
631
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
632
+ ];
633
+ const mockData = [
634
+ {
635
+ exists: true,
636
+ fixed: false,
637
+ toAmount: 2,
638
+ fromAmount: 1,
639
+ duration: "10-20",
640
+ max: 4,
641
+ min: 0.1,
642
+ },
643
+ ];
644
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
645
+
646
+ const result = await swapspaceSwapProvider.getSwapInfo(
647
+ BTC,
648
+ ETH,
649
+ "10",
650
+ false,
651
+ "2"
652
+ );
653
+
654
+ result.result.should.be.true();
655
+ result.min.should.be.equal("0.6");
656
+ });
657
+
658
+ it("should increase the smallestMin with coinAmountForMinMaxSafety", async () => {
659
+ swapspaceSwapProvider._supportedCoins = [
660
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
661
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
662
+ ];
663
+ const mockData = [
664
+ {
665
+ exists: true,
666
+ fixed: false,
667
+ toAmount: 2,
668
+ fromAmount: 1,
669
+ duration: "10-20",
670
+ max: 4,
671
+ min: 0.01,
672
+ },
673
+ {
674
+ exists: true,
675
+ fixed: false,
676
+ toAmount: 2,
677
+ fromAmount: 1,
678
+ duration: "10-20",
679
+ max: 4,
680
+ min: 0.2,
681
+ },
682
+ ];
683
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
684
+
685
+ const result = await swapspaceSwapProvider.getSwapInfo(
686
+ BTC,
687
+ ETH,
688
+ "10",
689
+ false,
690
+ "2"
691
+ );
692
+
693
+ result.result.should.be.true();
694
+ result.smallestMin.should.be.equal("0.51");
695
+ });
696
+
697
+ it("should set greatestMax to 0 if greatestMax - coinAmountForMinMaxSafety is negative", async () => {
698
+ swapspaceSwapProvider._supportedCoins = [
699
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
700
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
701
+ ];
702
+ const mockData = [
703
+ {
704
+ exists: true,
705
+ fixed: false,
706
+ toAmount: 2,
707
+ fromAmount: 1,
708
+ duration: "10-20",
709
+ max: 0.4,
710
+ min: 0.1,
711
+ },
712
+ {
713
+ exists: true,
714
+ fixed: false,
715
+ toAmount: 2,
716
+ fromAmount: 1,
717
+ duration: "10-20",
718
+ max: 0.3,
719
+ min: 0.1,
720
+ },
721
+ ];
722
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
723
+
724
+ const result = await swapspaceSwapProvider.getSwapInfo(
725
+ BTC,
726
+ ETH,
727
+ "10",
728
+ false,
729
+ "2"
730
+ );
731
+
732
+ result.result.should.be.true();
733
+ result.greatestMax.should.be.equal("0");
734
+ });
735
+
736
+ it("should decrease the max with coinAmountForMinMaxSafety", async () => {
737
+ swapspaceSwapProvider._supportedCoins = [
738
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
739
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
740
+ ];
741
+ const mockData = [
742
+ {
743
+ exists: true,
744
+ fixed: false,
745
+ toAmount: 2,
746
+ fromAmount: 1,
747
+ duration: "10-20",
748
+ max: 4,
749
+ min: 0.1,
750
+ },
751
+ ];
752
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
753
+
754
+ const result = await swapspaceSwapProvider.getSwapInfo(
755
+ BTC,
756
+ ETH,
757
+ "10",
758
+ false,
759
+ "2"
760
+ );
761
+
762
+ result.result.should.be.true();
763
+ result.max.should.be.equal("3.5");
764
+ });
765
+
766
+ it("should decrease the greatestMax with coinAmountForMinMaxSafety", async () => {
767
+ swapspaceSwapProvider._supportedCoins = [
768
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
769
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
770
+ ];
771
+ const mockData = [
772
+ {
773
+ exists: true,
774
+ fixed: false,
775
+ toAmount: 2,
776
+ fromAmount: 1,
777
+ duration: "10-20",
778
+ max: 4,
779
+ min: 0.1,
780
+ },
781
+ {
782
+ exists: true,
783
+ fixed: false,
784
+ toAmount: 2,
785
+ fromAmount: 1,
786
+ duration: "10-20",
787
+ max: 6,
788
+ min: 0.1,
789
+ },
790
+ ];
791
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
792
+
793
+ const result = await swapspaceSwapProvider.getSwapInfo(
794
+ BTC,
795
+ ETH,
796
+ "10",
797
+ false,
798
+ "2"
799
+ );
800
+
801
+ result.result.should.be.true();
802
+ result.greatestMax.should.be.equal("5.5");
803
+ });
804
+
805
+ it("should set max to 0 if max - coinAmountForMinMaxSafety is negative", async () => {
806
+ swapspaceSwapProvider._supportedCoins = [
807
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
808
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
809
+ ];
810
+ const mockData = [
811
+ {
812
+ exists: true,
813
+ fixed: false,
814
+ toAmount: 2,
815
+ fromAmount: 1,
816
+ duration: "10-20",
817
+ max: 0.4,
818
+ min: 0.1,
819
+ },
820
+ ];
821
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
822
+
823
+ const result = await swapspaceSwapProvider.getSwapInfo(
824
+ BTC,
825
+ ETH,
826
+ "10",
827
+ false,
828
+ "2"
829
+ );
830
+
831
+ result.result.should.be.true();
832
+ result.max.should.be.equal("0");
833
+ });
834
+
835
+ it("should filter out exchanges without toAmount", async () => {
836
+ swapspaceSwapProvider._supportedCoins = [
837
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
838
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
839
+ ];
840
+ const mockData = [
841
+ {
842
+ exists: true,
843
+ fixed: false,
844
+ duration: "10-20",
845
+ max: 5,
846
+ min: 0.1,
847
+ },
848
+ ];
849
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
850
+
851
+ const result = await swapspaceSwapProvider.getSwapInfo(
852
+ BTC,
853
+ ETH,
854
+ "1"
855
+ );
856
+
857
+ result.result.should.be.false();
858
+ result.reason.should.be.equal(
859
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
860
+ );
861
+ });
862
+
863
+ it("should filter out banned exchanges", async () => {
864
+ swapspaceSwapProvider._supportedCoins = [
865
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
866
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
867
+ ];
868
+ const mockData = [
869
+ {
870
+ id: "",
871
+ supportRate: 2,
872
+ duration: "11-38",
873
+ min: 0.00029295,
874
+ max: 0,
875
+ fixed: false,
876
+ partner: "stealthex",
877
+ exists: true,
878
+ fromAmount: 0.1,
879
+ fromCurrency: "btc",
880
+ fromNetwork: "btc",
881
+ toAmount: 1.3223873,
882
+ toCurrency: "eth",
883
+ toNetwork: "eth",
884
+ },
885
+ ];
886
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
887
+
888
+ const result = await swapspaceSwapProvider.getSwapInfo(
889
+ BTC,
890
+ ETH,
891
+ "1"
892
+ );
893
+
894
+ result.result.should.be.false();
895
+ result.reason.should.be.equal(
896
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
897
+ );
898
+ });
899
+
900
+ it("should filter out exchanges where toAmount equals 0", async () => {
901
+ swapspaceSwapProvider._supportedCoins = [
902
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
903
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
904
+ ];
905
+ const mockData = [
906
+ {
907
+ exists: true,
908
+ toAmount: 0,
909
+ fixed: false,
910
+ duration: "10-20",
911
+ max: 5,
912
+ min: 0.1,
913
+ },
914
+ ];
915
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
916
+
917
+ const result = await swapspaceSwapProvider.getSwapInfo(
918
+ BTC,
919
+ ETH,
920
+ "1"
921
+ );
922
+
923
+ result.result.should.be.false();
924
+ result.reason.should.be.equal(
925
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
926
+ );
927
+ });
928
+
929
+ it("should correctly compute smallestMin and greatestMax", async () => {
930
+ swapspaceSwapProvider._supportedCoins = [
931
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
932
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
933
+ ];
934
+ const mockData = [
935
+ {
936
+ exists: true,
937
+ fixed: false,
938
+ toAmount: 3,
939
+ fromAmount: 1,
940
+ duration: "10-20",
941
+ max: 3,
942
+ min: 0.5,
943
+ },
944
+ {
945
+ exists: true,
946
+ fixed: false,
947
+ toAmount: 2,
948
+ fromAmount: 1,
949
+ duration: "10-20",
950
+ max: 5,
951
+ min: 1,
952
+ },
953
+ ];
954
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
955
+
956
+ const result = await swapspaceSwapProvider.getSwapInfo(
957
+ BTC,
958
+ ETH,
959
+ "1",
960
+ false,
961
+ "2"
962
+ );
963
+
964
+ result.smallestMin.should.be.above(0.5);
965
+ result.greatestMax.should.be.below(5);
966
+ });
967
+
968
+ it("should handle general axios error", async () => {
969
+ swapspaceSwapProvider._supportedCoins = [
970
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
971
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
972
+ ];
973
+ const error = new Error();
974
+ error.response = { status: 500 };
975
+ axiosGetStub.throws(error);
976
+
977
+ try {
978
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
979
+ } catch (error) {
980
+ error.should.be.an.instanceof(Error);
981
+ }
982
+ });
983
+
984
+ it("should handle missing data in axios response", async () => {
985
+ swapspaceSwapProvider._supportedCoins = [
986
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
987
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
988
+ ];
989
+ axiosGetStub.returns(Promise.resolve({}));
990
+
991
+ const result = await swapspaceSwapProvider.getSwapInfo(
992
+ BTC,
993
+ ETH,
994
+ "1"
995
+ );
996
+
997
+ result.result.should.be.false();
998
+ result.reason.should.be.equal(
999
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1000
+ );
1001
+ });
1002
+
1003
+ it("should handle non-array axios response data", async () => {
1004
+ swapspaceSwapProvider._supportedCoins = [
1005
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1006
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1007
+ ];
1008
+ axiosGetStub.returns(Promise.resolve({ data: {} }));
1009
+
1010
+ const result = await swapspaceSwapProvider.getSwapInfo(
1011
+ BTC,
1012
+ ETH,
1013
+ "1"
1014
+ );
1015
+
1016
+ result.result.should.be.false();
1017
+ result.reason.should.be.equal(
1018
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1019
+ );
1020
+ });
1021
+
1022
+ it("should handle missing exists property in exchange data", async () => {
1023
+ swapspaceSwapProvider._supportedCoins = [
1024
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1025
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1026
+ ];
1027
+ const mockData = [
1028
+ {
1029
+ fixed: false,
1030
+ toAmount: 2,
1031
+ fromAmount: 1,
1032
+ duration: "10-20",
1033
+ max: 5,
1034
+ min: 0.1,
1035
+ },
1036
+ ];
1037
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1038
+
1039
+ const result = await swapspaceSwapProvider.getSwapInfo(
1040
+ BTC,
1041
+ ETH,
1042
+ "1"
1043
+ );
1044
+
1045
+ result.result.should.be.false();
1046
+ result.reason.should.be.equal(
1047
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1048
+ );
1049
+ });
1050
+
1051
+ it("should handle missing fixed property in exchange data", async () => {
1052
+ swapspaceSwapProvider._supportedCoins = [
1053
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1054
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1055
+ ];
1056
+ const mockData = [
1057
+ {
1058
+ exists: true,
1059
+ toAmount: 2,
1060
+ fromAmount: 1,
1061
+ duration: "10-20",
1062
+ max: 5,
1063
+ min: 0.1,
1064
+ },
1065
+ ];
1066
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1067
+
1068
+ const result = await swapspaceSwapProvider.getSwapInfo(
1069
+ BTC,
1070
+ ETH,
1071
+ "1"
1072
+ );
1073
+
1074
+ result.result.should.be.false();
1075
+ result.reason.should.be.equal(
1076
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1077
+ );
1078
+ });
1079
+
1080
+ it("should capture exchanges with exist=false as not supporting the pair", async () => {
1081
+ swapspaceSwapProvider._supportedCoins = [
1082
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1083
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1084
+ ];
1085
+ const mockData = [
1086
+ {
1087
+ exists: false,
1088
+ fixed: false,
1089
+ toAmount: 200,
1090
+ fromAmount: 1,
1091
+ duration: "9-21",
1092
+ max: 51,
1093
+ min: 0.11,
1094
+ },
1095
+ {
1096
+ exists: false,
1097
+ fixed: false,
1098
+ toAmount: 300,
1099
+ fromAmount: 1,
1100
+ duration: "12-22",
1101
+ max: 15,
1102
+ min: 0.13,
1103
+ },
1104
+ {
1105
+ exists: true,
1106
+ fixed: false,
1107
+ toAmount: 2,
1108
+ fromAmount: 1,
1109
+ duration: "11-23",
1110
+ max: 11,
1111
+ min: 0.12,
1112
+ },
1113
+ ];
1114
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1115
+
1116
+ const result = await swapspaceSwapProvider.getSwapInfo(
1117
+ BTC,
1118
+ ETH,
1119
+ "1"
1120
+ );
1121
+
1122
+ result.result.should.be.true();
1123
+ result.rawSwapData.should.be.equal(mockData[2]);
1124
+ });
1125
+
1126
+ it("should consider missing exists property as not supporting the pair", async () => {
1127
+ swapspaceSwapProvider._supportedCoins = [
1128
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1129
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1130
+ ];
1131
+ const mockData = [
1132
+ {
1133
+ fixed: false,
1134
+ toAmount: 2,
1135
+ fromAmount: 1,
1136
+ duration: "10-20",
1137
+ max: 5,
1138
+ min: 0.1,
1139
+ },
1140
+ ];
1141
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1142
+
1143
+ const result = await swapspaceSwapProvider.getSwapInfo(
1144
+ BTC,
1145
+ ETH,
1146
+ "1"
1147
+ );
1148
+
1149
+ result.result.should.be.false();
1150
+ result.reason.should.be.equal(
1151
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1152
+ );
1153
+ });
1154
+
1155
+ it("should return null rate when fromAmount is not number greater than 0", async () => {
1156
+ swapspaceSwapProvider._supportedCoins = [
1157
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1158
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1159
+ ];
1160
+ const mockData = [
1161
+ {
1162
+ exists: true,
1163
+ fixed: false,
1164
+ toAmount: 3,
1165
+ fromAmount: 0,
1166
+ duration: "10-20",
1167
+ max: 5,
1168
+ min: 0.1,
1169
+ },
1170
+ ];
1171
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1172
+
1173
+ const result = await swapspaceSwapProvider.getSwapInfo(
1174
+ BTC,
1175
+ ETH,
1176
+ "1"
1177
+ );
1178
+
1179
+ (result.rate === null).should.be.true();
1180
+ });
1181
+
1182
+ it("should return null rate when toAmount is not number greater than 0 in response", async () => {
1183
+ swapspaceSwapProvider._supportedCoins = [
1184
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1185
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1186
+ ];
1187
+ const mockData = [
1188
+ {
1189
+ exists: true,
1190
+ fixed: false,
1191
+ toAmount: 3,
1192
+ fromAmount: 0,
1193
+ duration: "10-20",
1194
+ max: 5,
1195
+ min: 0.1,
1196
+ },
1197
+ ];
1198
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1199
+
1200
+ const result = await swapspaceSwapProvider.getSwapInfo(
1201
+ BTC,
1202
+ ETH,
1203
+ "1"
1204
+ );
1205
+
1206
+ (result.rate === null).should.be.true();
1207
+ });
1208
+
1209
+ it("should use an exchange with min=0 as unlimited", async () => {
1210
+ swapspaceSwapProvider._supportedCoins = [
1211
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1212
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1213
+ ];
1214
+ const mockData = [
1215
+ {
1216
+ exists: true,
1217
+ fixed: false,
1218
+ toAmount: 2,
1219
+ fromAmount: 1,
1220
+ duration: "10-20",
1221
+ max: 1000,
1222
+ min: 0,
1223
+ },
1224
+ ];
1225
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1226
+
1227
+ const result = await swapspaceSwapProvider.getSwapInfo(
1228
+ BTC,
1229
+ ETH,
1230
+ "100"
1231
+ );
1232
+
1233
+ result.result.should.be.true();
1234
+ (result.smallestMin === null).should.be.true();
1235
+ });
1236
+
1237
+ it("should use an exchange with max=0 as unlimited", async () => {
1238
+ swapspaceSwapProvider._supportedCoins = [
1239
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1240
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1241
+ ];
1242
+ const mockData = [
1243
+ {
1244
+ exists: true,
1245
+ fixed: false,
1246
+ toAmount: 2,
1247
+ fromAmount: 1,
1248
+ duration: "10-20",
1249
+ max: 0,
1250
+ min: 0.1,
1251
+ },
1252
+ ];
1253
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1254
+
1255
+ const result = await swapspaceSwapProvider.getSwapInfo(
1256
+ BTC,
1257
+ ETH,
1258
+ "100"
1259
+ );
1260
+
1261
+ result.result.should.be.true();
1262
+ (result.greatestMax === null).should.be.true();
1263
+ });
1264
+
1265
+ it("should set greatestMax based on availableExchanges when no exchange has max=0", async () => {
1266
+ swapspaceSwapProvider._supportedCoins = [
1267
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1268
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1269
+ ];
1270
+ const mockData = [
1271
+ {
1272
+ exists: true,
1273
+ fixed: false,
1274
+ toAmount: 2,
1275
+ fromAmount: 1,
1276
+ duration: "10-20",
1277
+ max: 10,
1278
+ min: 0.1,
1279
+ },
1280
+ {
1281
+ exists: true,
1282
+ fixed: false,
1283
+ toAmount: 3,
1284
+ fromAmount: 1,
1285
+ duration: "10-20",
1286
+ max: 5,
1287
+ min: 0.5,
1288
+ },
1289
+ ];
1290
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1291
+
1292
+ const result = await swapspaceSwapProvider.getSwapInfo(
1293
+ BTC,
1294
+ ETH,
1295
+ "5",
1296
+ false,
1297
+ "2"
1298
+ );
1299
+
1300
+ result.greatestMax.should.be.below(10);
1301
+ });
1302
+
1303
+ it("should handle exchanges with non-numeric toAmount", async () => {
1304
+ swapspaceSwapProvider._supportedCoins = [
1305
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1306
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1307
+ ];
1308
+ const mockData = [
1309
+ {
1310
+ exists: true,
1311
+ fixed: false,
1312
+ toAmount: "invalid",
1313
+ fromAmount: 1,
1314
+ duration: "10-20",
1315
+ max: 5,
1316
+ min: 0.1,
1317
+ },
1318
+ ];
1319
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1320
+
1321
+ const result = await swapspaceSwapProvider.getSwapInfo(
1322
+ BTC,
1323
+ ETH,
1324
+ "1"
1325
+ );
1326
+
1327
+ result.result.should.be.false();
1328
+ result.reason.should.be.equal(
1329
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1330
+ );
1331
+ });
1332
+
1333
+ it("should correct smallestMin and greatestMax using coinAmountForMinMaxSafety", async () => {
1334
+ swapspaceSwapProvider._supportedCoins = [
1335
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1336
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1337
+ ];
1338
+ const mockData = [
1339
+ {
1340
+ exists: true,
1341
+ fixed: false,
1342
+ toAmount: 3,
1343
+ fromAmount: 1,
1344
+ duration: "10-20",
1345
+ max: 5,
1346
+ min: 0.5,
1347
+ },
1348
+ ];
1349
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1350
+
1351
+ const result = await swapspaceSwapProvider.getSwapInfo(
1352
+ BTC,
1353
+ ETH,
1354
+ "1",
1355
+ false,
1356
+ "2"
1357
+ );
1358
+
1359
+ result.smallestMin.should.be.above(0.5);
1360
+ result.greatestMax.should.be.below(5);
1361
+ });
1362
+
1363
+ it("should treat min=0 from an exchange as no limit", async () => {
1364
+ swapspaceSwapProvider._supportedCoins = [
1365
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1366
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1367
+ ];
1368
+ const mockData = [
1369
+ {
1370
+ exists: true,
1371
+ fixed: false,
1372
+ toAmount: 2,
1373
+ fromAmount: 1,
1374
+ duration: "10-20",
1375
+ max: 1,
1376
+ min: 0,
1377
+ },
1378
+ ];
1379
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1380
+
1381
+ const result = await swapspaceSwapProvider.getSwapInfo(
1382
+ BTC,
1383
+ ETH,
1384
+ "1"
1385
+ );
1386
+
1387
+ (result.min === null).should.be.true();
1388
+ });
1389
+
1390
+ it("should treat max=0 from an exchange as no limit", async () => {
1391
+ swapspaceSwapProvider._supportedCoins = [
1392
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1393
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1394
+ ];
1395
+ const mockData = [
1396
+ {
1397
+ exists: true,
1398
+ fixed: false,
1399
+ toAmount: 2,
1400
+ fromAmount: 1,
1401
+ duration: "10-20",
1402
+ max: 0,
1403
+ min: 1,
1404
+ },
1405
+ ];
1406
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1407
+
1408
+ const result = await swapspaceSwapProvider.getSwapInfo(
1409
+ BTC,
1410
+ ETH,
1411
+ "1"
1412
+ );
1413
+
1414
+ (result.max === null).should.be.true();
1415
+ });
1416
+
1417
+ it("should consider min > max as an invalid exchange option", async () => {
1418
+ swapspaceSwapProvider._supportedCoins = [
1419
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1420
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1421
+ ];
1422
+ const mockData = [
1423
+ {
1424
+ exists: true,
1425
+ fixed: false,
1426
+ toAmount: 2,
1427
+ fromAmount: 1,
1428
+ duration: "10-20",
1429
+ max: 1,
1430
+ min: 5,
1431
+ },
1432
+ ];
1433
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1434
+
1435
+ const result = await swapspaceSwapProvider.getSwapInfo(
1436
+ BTC,
1437
+ ETH,
1438
+ "3"
1439
+ );
1440
+
1441
+ result.result.should.be.false();
1442
+ result.reason.should.be.equal(
1443
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1444
+ );
1445
+ });
1446
+
1447
+ it("should handle not null/undefined coin->usd rate - safety coin amount should be used as 0", async () => {
1448
+ swapspaceSwapProvider._supportedCoins = [
1449
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1450
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1451
+ ];
1452
+ const mockData = [
1453
+ {
1454
+ exists: true,
1455
+ fixed: false,
1456
+ toAmount: 2,
1457
+ fromAmount: 1,
1458
+ duration: "10-20",
1459
+ max: 5,
1460
+ min: 0.1,
1461
+ },
1462
+ ];
1463
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1464
+
1465
+ const result = await swapspaceSwapProvider.getSwapInfo(
1466
+ BTC,
1467
+ ETH,
1468
+ "1",
1469
+ false,
1470
+ "2"
1471
+ );
1472
+
1473
+ result.result.should.be.true();
1474
+ result.min.should.be.equal("0.6");
1475
+ result.max.should.be.equal("4.5");
1476
+ result.smallestMin.should.be.equal("0.6");
1477
+ result.greatestMax.should.be.equal("4.5");
1478
+ });
1479
+
1480
+ it("should handle null coin->usd rate - safety coin amount should be used as 0", async () => {
1481
+ swapspaceSwapProvider._supportedCoins = [
1482
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1483
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1484
+ ];
1485
+ const mockData = [
1486
+ {
1487
+ exists: true,
1488
+ fixed: false,
1489
+ toAmount: 2,
1490
+ fromAmount: 1,
1491
+ duration: "10-20",
1492
+ max: 5,
1493
+ min: 0.1,
1494
+ },
1495
+ ];
1496
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1497
+
1498
+ const result = await swapspaceSwapProvider.getSwapInfo(
1499
+ BTC,
1500
+ ETH,
1501
+ "1"
1502
+ );
1503
+
1504
+ result.result.should.be.true();
1505
+ result.min.should.be.equal("0.1");
1506
+ result.max.should.be.equal("5");
1507
+ result.smallestMin.should.be.equal("0.1");
1508
+ result.greatestMax.should.be.equal("5");
1509
+ });
1510
+
1511
+ it("should consider an exchange with negative toAmount as not supporting the pair", async () => {
1512
+ swapspaceSwapProvider._supportedCoins = [
1513
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1514
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1515
+ ];
1516
+ const mockData = [
1517
+ {
1518
+ exists: true,
1519
+ fixed: false,
1520
+ toAmount: -2,
1521
+ fromAmount: 1,
1522
+ duration: "10-20",
1523
+ max: 5,
1524
+ min: 0.1,
1525
+ },
1526
+ ];
1527
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1528
+
1529
+ const result = await swapspaceSwapProvider.getSwapInfo(
1530
+ BTC,
1531
+ ETH,
1532
+ "1"
1533
+ );
1534
+
1535
+ result.result.should.be.false();
1536
+ result.reason.should.be.equal(
1537
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1538
+ );
1539
+ });
1540
+
1541
+ it("should correctly account for coinAmountForMinMaxSafety in rate calculation", async () => {
1542
+ swapspaceSwapProvider._supportedCoins = [
1543
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1544
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1545
+ ];
1546
+ const mockData = [
1547
+ {
1548
+ exists: true,
1549
+ fixed: false,
1550
+ toAmount: 3,
1551
+ fromAmount: 2,
1552
+ duration: "10-20",
1553
+ max: 1,
1554
+ min: 0.1,
1555
+ },
1556
+ ];
1557
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1558
+
1559
+ const result = await swapspaceSwapProvider.getSwapInfo(
1560
+ BTC,
1561
+ ETH,
1562
+ "0.9",
1563
+ false,
1564
+ "2"
1565
+ );
1566
+
1567
+ result.min.should.be.above(0.1);
1568
+ });
1569
+
1570
+ it("should handle scenario where all exchanges have negative toAmount", async () => {
1571
+ swapspaceSwapProvider._supportedCoins = [
1572
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1573
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1574
+ ];
1575
+ const mockData = [
1576
+ {
1577
+ exists: true,
1578
+ fixed: false,
1579
+ toAmount: -2,
1580
+ fromAmount: 1,
1581
+ duration: "10-20",
1582
+ max: 5,
1583
+ min: 0.1,
1584
+ },
1585
+ {
1586
+ exists: true,
1587
+ fixed: false,
1588
+ toAmount: -3,
1589
+ fromAmount: 1,
1590
+ duration: "10-20",
1591
+ max: 6,
1592
+ min: 0.2,
1593
+ },
1594
+ ];
1595
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1596
+
1597
+ const result = await swapspaceSwapProvider.getSwapInfo(
1598
+ BTC,
1599
+ ETH,
1600
+ "1"
1601
+ );
1602
+
1603
+ result.result.should.be.false();
1604
+ result.reason.should.be.equal(
1605
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1606
+ );
1607
+ });
1608
+
1609
+ it("should use the best exchange option according to toAmount", async () => {
1610
+ swapspaceSwapProvider._supportedCoins = [
1611
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1612
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1613
+ ];
1614
+ const mockData = [
1615
+ {
1616
+ exists: true,
1617
+ fixed: false,
1618
+ toAmount: 3.1,
1619
+ fromAmount: 1,
1620
+ duration: "11-21",
1621
+ max: 5,
1622
+ min: 0.1,
1623
+ },
1624
+ {
1625
+ exists: true,
1626
+ fixed: false,
1627
+ toAmount: 3,
1628
+ fromAmount: 1,
1629
+ duration: "10-20",
1630
+ max: 6,
1631
+ min: 0.2,
1632
+ },
1633
+ ];
1634
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1635
+
1636
+ const result = await swapspaceSwapProvider.getSwapInfo(
1637
+ BTC,
1638
+ ETH,
1639
+ "1"
1640
+ );
1641
+
1642
+ result.durationMinutesRange.should.be.equal("11-21");
1643
+ });
1644
+
1645
+ it(`should use toNetwork from _supportedCoins`, async () => {
1646
+ const expToNetwork = "slkjfn2";
1647
+ swapspaceSwapProvider._supportedCoins = [
1648
+ { coin: BTC, network: "btc" },
1649
+ { coin: ETH, network: expToNetwork },
1650
+ ];
1651
+ axiosGetStub.callsFake((url) => {
1652
+ url.includes(`&toNetwork=${expToNetwork}&`).should.be.true();
1653
+ return Promise.resolve({ data: [] });
1654
+ });
1655
+
1656
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1657
+ });
1658
+
1659
+ it(`should use fromNetwork from _supportedCoins`, async () => {
1660
+ const expNetwork = "slkjfn2";
1661
+ swapspaceSwapProvider._supportedCoins = [
1662
+ { coin: BTC, network: expNetwork },
1663
+ { coin: ETH, network: "eth" },
1664
+ ];
1665
+ axiosGetStub.callsFake((url) => {
1666
+ url.includes(`&fromNetwork=${expNetwork}&`).should.be.true();
1667
+ return Promise.resolve({ data: [] });
1668
+ });
1669
+
1670
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1671
+ });
1672
+
1673
+ it("should respect the estimated=false parameter in the axios request", async () => {
1674
+ swapspaceSwapProvider._supportedCoins = [
1675
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1676
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1677
+ ];
1678
+ axiosGetStub.callsFake((url) => {
1679
+ url.includes("estimated=false").should.be.true();
1680
+ return Promise.resolve({ data: [] });
1681
+ });
1682
+
1683
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1684
+ });
1685
+
1686
+ it("should not convey float or fixed parameters in the axios request", async () => {
1687
+ swapspaceSwapProvider._supportedCoins = [
1688
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1689
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1690
+ ];
1691
+ axiosGetStub.callsFake((url) => {
1692
+ url.should.not.containEql("float=");
1693
+ url.should.not.containEql("fixed=");
1694
+ return Promise.resolve({ data: [] });
1695
+ });
1696
+
1697
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1698
+ });
1699
+
1700
+ it("should respect amount parameter in the axios request", async () => {
1701
+ swapspaceSwapProvider._supportedCoins = [
1702
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1703
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1704
+ ];
1705
+ axiosGetStub.callsFake((url) => {
1706
+ url.should.containEql("amount=1");
1707
+ return Promise.resolve({ data: [] });
1708
+ });
1709
+
1710
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1711
+ });
1712
+
1713
+ it("should pass the from code from supportedCoins as parameter in the axios request", async () => {
1714
+ swapspaceSwapProvider._supportedCoins = [
1715
+ { coin: BTC, code: "aaa", network: "btc" },
1716
+ { coin: ETH, code: "eth", network: "eth" },
1717
+ ];
1718
+ axiosGetStub.callsFake((url) => {
1719
+ url.should.containEql(`fromCurrency=aaa&`);
1720
+ return Promise.resolve({ data: [] });
1721
+ });
1722
+
1723
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1724
+ });
1725
+
1726
+ it("should pass the to code from supportedCoins as parameter in the axios request", async () => {
1727
+ swapspaceSwapProvider._supportedCoins = [
1728
+ { coin: BTC, code: "btc", network: "btc" },
1729
+ { coin: ETH, code: "aaa", network: "eth" },
1730
+ ];
1731
+ axiosGetStub.callsFake((url) => {
1732
+ url.should.containEql(`toCurrency=aaa&`);
1733
+ return Promise.resolve({ data: [] });
1734
+ });
1735
+
1736
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1737
+ });
1738
+
1739
+ it("should generate correct URL for TRX to ERC20 USDT swap", async () => {
1740
+ swapspaceSwapProvider._supportedCoins = [
1741
+ { coin: TRX, code: "trx", network: "trx" },
1742
+ { coin: USDTERC20, code: "usdt", network: "erc20" },
1743
+ ];
1744
+ axiosGetStub.callsFake((url) => {
1745
+ url.should.containEql(`/api/v2/amounts`);
1746
+ url.should.containEql("fromCurrency=trx");
1747
+ url.should.containEql("fromNetwork=trx");
1748
+ url.should.containEql("toCurrency=usdt");
1749
+ url.should.containEql("toNetwork=erc20");
1750
+ url.should.containEql("amount=100");
1751
+ url.should.containEql("float=true");
1752
+ url.should.containEql("estimated=false");
1753
+ return Promise.resolve({ data: [] });
1754
+ });
1755
+
1756
+ await swapspaceSwapProvider.getSwapInfo(TRX, USDTERC20, "100");
1757
+ });
1758
+
1759
+ it("should generate correct URL for BTC to ETH swap", async () => {
1760
+ swapspaceSwapProvider._supportedCoins = [
1761
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1762
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1763
+ ];
1764
+ axiosGetStub.callsFake((url) => {
1765
+ url.should.containEql(`/api/v2/amounts`);
1766
+ url.should.containEql("fromCurrency=btc");
1767
+ url.should.containEql("fromNetwork=btc");
1768
+ url.should.containEql("toCurrency=eth");
1769
+ url.should.containEql("toNetwork=eth");
1770
+ url.should.containEql("amount=1");
1771
+ url.should.containEql("estimated=false");
1772
+ return Promise.resolve({ data: [] });
1773
+ });
1774
+
1775
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1776
+ });
1777
+
1778
+ it("should generate correct URL for TRC20 USDC to BTC swap", async () => {
1779
+ swapspaceSwapProvider._supportedCoins = [
1780
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1781
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1782
+ { coin: USDCTRC20, code: "usdc", network: "trc20" },
1783
+ ];
1784
+ axiosGetStub.callsFake((url) => {
1785
+ url.should.containEql(`/api/v2/amounts`);
1786
+ url.should.containEql("fromCurrency=usdc");
1787
+ url.should.containEql("fromNetwork=trc20");
1788
+ url.should.containEql("toCurrency=btc");
1789
+ url.should.containEql("toNetwork=btc");
1790
+ url.should.containEql("amount=50.0235");
1791
+ url.should.containEql("float=true");
1792
+ url.should.containEql("estimated=false");
1793
+ return Promise.resolve({ data: [] });
1794
+ });
1795
+
1796
+ await swapspaceSwapProvider.getSwapInfo(USDCTRC20, BTC, "50.0235");
1797
+ });
1798
+
1799
+ it("should return null for durationMinutesRange if bestRateOption does not contain the duration property", async () => {
1800
+ swapspaceSwapProvider._supportedCoins = [
1801
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1802
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1803
+ ];
1804
+ const mockData = [
1805
+ {
1806
+ exists: true,
1807
+ fixed: false,
1808
+ toAmount: 3,
1809
+ fromAmount: 1,
1810
+ max: 5,
1811
+ min: 0.1,
1812
+ },
1813
+ ];
1814
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1815
+
1816
+ const result = await swapspaceSwapProvider.getSwapInfo(
1817
+ BTC,
1818
+ ETH,
1819
+ "1"
1820
+ );
1821
+
1822
+ (result.durationMinutesRange === null).should.be.true();
1823
+ });
1824
+
1825
+ it("should throw error when passing coins with unknown tickers or protocols", async () => {
1826
+ try {
1827
+ await swapspaceSwapProvider.getSwapInfo(
1828
+ { ticker: "unknownCoin" },
1829
+ ETH,
1830
+ "1"
1831
+ );
1832
+ } catch (error) {
1833
+ error.should.be.an.instanceof(Error);
1834
+ }
1835
+ });
1836
+
1837
+ it("should throw error for non-string amountCoins input", async () => {
1838
+ try {
1839
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, "1");
1840
+ } catch (error) {
1841
+ error.should.be.an.instanceof(Error);
1842
+ }
1843
+ });
1844
+
1845
+ it("should throw error for negative amountCoins input", async () => {
1846
+ try {
1847
+ await swapspaceSwapProvider.getSwapInfo(BTC, ETH, -1);
1848
+ } catch (error) {
1849
+ error.should.be.an.instanceof(Error);
1850
+ }
1851
+ });
1852
+
1853
+ it("should handle scenario where all exchanges have non-string toAmount and fromAmount", async () => {
1854
+ swapspaceSwapProvider._supportedCoins = [
1855
+ { coin: BTC, code: "btc", network: "btc", deposit: true },
1856
+ { coin: ETH, code: "eth", network: "eth", withdrawal: true },
1857
+ ];
1858
+ const mockData = [
1859
+ {
1860
+ exists: true,
1861
+ fixed: false,
1862
+ toAmount: "invalid",
1863
+ fromAmount: "invalid",
1864
+ duration: "10-20",
1865
+ max: 5,
1866
+ min: 0.1,
1867
+ },
1868
+ {
1869
+ exists: true,
1870
+ fixed: false,
1871
+ toAmount: "invalid",
1872
+ fromAmount: "invalid",
1873
+ duration: "10-20",
1874
+ max: 6,
1875
+ min: 0.2,
1876
+ },
1877
+ ];
1878
+ axiosGetStub.returns(Promise.resolve({ data: mockData }));
1879
+
1880
+ const result = await swapspaceSwapProvider.getSwapInfo(
1881
+ BTC,
1882
+ ETH,
1883
+ "1"
1884
+ );
1885
+
1886
+ result.result.should.be.false();
1887
+ result.reason.should.be.equal(
1888
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
1889
+ );
1890
+ });
1891
+ });
1892
+ });