@rabbitio/ui-kit 1.0.0-beta.4 → 1.0.0-beta.40

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 (55) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/README.md +23 -16
  3. package/dist/index.cjs +5336 -9
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +4480 -1635
  6. package/dist/index.css.map +1 -1
  7. package/dist/index.modern.js +3766 -11
  8. package/dist/index.modern.js.map +1 -1
  9. package/dist/index.module.js +5298 -11
  10. package/dist/index.module.js.map +1 -1
  11. package/dist/index.umd.js +5335 -12
  12. package/dist/index.umd.js.map +1 -1
  13. package/index.js +1 -1
  14. package/package.json +16 -22
  15. package/src/common/adapters/axiosAdapter.js +35 -0
  16. package/src/common/amountUtils.js +434 -0
  17. package/src/common/errorUtils.js +42 -0
  18. package/src/common/external-apis/apiGroups.js +55 -0
  19. package/src/common/fiatCurrenciesService.js +161 -0
  20. package/src/common/models/blockchain.js +10 -0
  21. package/src/common/models/coin.js +157 -0
  22. package/src/common/models/protocol.js +5 -0
  23. package/src/common/utils/cache.js +268 -0
  24. package/src/common/utils/emailAPI.js +18 -0
  25. package/src/common/utils/logging/logger.js +48 -0
  26. package/src/common/utils/logging/logsStorage.js +61 -0
  27. package/src/common/utils/postponeExecution.js +11 -0
  28. package/src/common/utils/safeStringify.js +50 -0
  29. package/src/components/atoms/AssetIcon/AssetIcon.jsx +55 -0
  30. package/src/components/atoms/AssetIcon/asset-icon.module.scss +42 -0
  31. package/{stories → src/components}/atoms/LoadingDots/LoadingDots.module.scss +1 -1
  32. package/src/components/atoms/SupportChat/SupportChat.jsx +48 -0
  33. package/{stories → src/components}/atoms/buttons/Button/Button.jsx +11 -7
  34. package/{stories → src/components}/atoms/buttons/Button/Button.module.scss +6 -1
  35. package/src/components/hooks/useCallHandlingErrors.js +26 -0
  36. package/src/components/hooks/useReferredState.js +24 -0
  37. package/src/components/utils/uiUtils.js +14 -0
  38. package/src/components/utils/urlQueryUtils.js +87 -0
  39. package/src/index.js +52 -0
  40. package/src/robustExteranlApiCallerService/cacheAndConcurrentRequestsResolver.js +559 -0
  41. package/src/robustExteranlApiCallerService/cachedRobustExternalApiCallerService.js +188 -0
  42. package/src/robustExteranlApiCallerService/cancelProcessing.js +29 -0
  43. package/src/robustExteranlApiCallerService/concurrentCalculationsMetadataHolder.js +103 -0
  44. package/src/robustExteranlApiCallerService/externalApiProvider.js +156 -0
  45. package/src/robustExteranlApiCallerService/externalServicesStatsCollector.js +82 -0
  46. package/src/robustExteranlApiCallerService/robustExternalAPICallerService.js +386 -0
  47. package/src/swaps-lib/external-apis/swapProvider.js +201 -0
  48. package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +877 -0
  49. package/src/swaps-lib/models/baseSwapCreationInfo.js +40 -0
  50. package/src/swaps-lib/models/existingSwap.js +70 -0
  51. package/src/swaps-lib/models/existingSwapWithFiatData.js +130 -0
  52. package/src/swaps-lib/services/publicSwapService.js +674 -0
  53. package/src/swaps-lib/utils/swapUtils.js +219 -0
  54. package/stories/index.js +0 -2
  55. /package/{stories → src/components}/atoms/LoadingDots/LoadingDots.jsx +0 -0
@@ -0,0 +1,674 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import EventBusInstance from "eventbusjs";
3
+
4
+ import { FiatCurrenciesService } from "../../common/fiatCurrenciesService.js";
5
+ import { improveAndRethrow } from "../../common/errorUtils.js";
6
+ import { safeStringify } from "../../common/utils/safeStringify.js";
7
+ import { Logger } from "../../common/utils/logging/logger.js";
8
+ import { Coin } from "../../common/models/coin.js";
9
+ import { AmountUtils } from "../../common/amountUtils.js";
10
+ import { BaseSwapCreationInfo } from "../models/baseSwapCreationInfo.js";
11
+ import { SwapUtils } from "../utils/swapUtils.js";
12
+ import { SwapspaceSwapProvider } from "../external-apis/swapspaceSwapProvider.js";
13
+ import { SwapProvider } from "../external-apis/swapProvider.js";
14
+
15
+ export class PublicSwapService {
16
+ static PUBLIC_SWAP_CREATED_EVENT = "publicSwapCreatedEvent";
17
+
18
+ static PUBLIC_SWAPS_COMMON_ERRORS = {
19
+ REQUESTS_LIMIT_EXCEEDED: "requestsLimitExceeded",
20
+ };
21
+
22
+ static PUBLIC_SWAP_DETAILS_FAIL_REASONS = {
23
+ AMOUNT_LESS_THAN_MIN_SWAPPABLE: "amountLessThanMinSwappable",
24
+ AMOUNT_HIGHER_THAN_MAX_SWAPPABLE: "amountHigherThanMaxSwappable",
25
+ PAIR_NOT_SUPPORTED: "pairNotSupported",
26
+ };
27
+
28
+ static _fiatDecimalsCount =
29
+ FiatCurrenciesService.getCurrencyDecimalCountByCode("USD");
30
+
31
+ constructor(apiKeysProxyUrl, cache) {
32
+ this._swapProvider = new SwapspaceSwapProvider(
33
+ apiKeysProxyUrl,
34
+ cache,
35
+ () => null,
36
+ false
37
+ );
38
+ }
39
+
40
+ async initialize() {
41
+ try {
42
+ await this._swapProvider.initialize();
43
+ } catch (e) {
44
+ Logger.logError(e, "PublicSwapService.initialize");
45
+ }
46
+ }
47
+
48
+ async getAllSupportedCurrenciesListForPublicSwap() {
49
+ const loggerSource = "getAllSupportedCurrenciesListForPublicSwap";
50
+ try {
51
+ const result = await this._swapProvider.getAllSupportedCurrencies();
52
+ if (
53
+ result.reason ===
54
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
55
+ ) {
56
+ SwapUtils.safeHandleRequestsLimitExceeding();
57
+ return {
58
+ result: false,
59
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS
60
+ .REQUESTS_LIMIT_EXCEEDED,
61
+ };
62
+ }
63
+ Logger.log(
64
+ `Retrieved ${result?.coins?.length} supported currencies for swap`,
65
+ loggerSource
66
+ );
67
+ return { result: true, coins: result.coins };
68
+ } catch (e) {
69
+ improveAndRethrow(e, "getDepositCurrenciesListForPublicSwap");
70
+ }
71
+ }
72
+
73
+ async getDepositCurrenciesListForPublicSwap() {
74
+ try {
75
+ return await this._getCurrenciesListForPublicSwap(false);
76
+ } catch (e) {
77
+ improveAndRethrow(e, "getDepositCurrenciesListForPublicSwap");
78
+ }
79
+ }
80
+
81
+ async getWithdrawCurrenciesListForPublicSwap() {
82
+ try {
83
+ return await this._getCurrenciesListForPublicSwap(true);
84
+ } catch (e) {
85
+ improveAndRethrow(e, "getWithdrawCurrenciesListForPublicSwap");
86
+ }
87
+ }
88
+
89
+ async _getCurrenciesListForPublicSwap(withdraw = false) {
90
+ const loggerSource = "getCurrenciesListForPublicSwap";
91
+ try {
92
+ const result = withdraw
93
+ ? await this._swapProvider.getWithdrawalCurrencies()
94
+ : await this._swapProvider.getDepositCurrencies();
95
+ if (
96
+ result.reason ===
97
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
98
+ ) {
99
+ SwapUtils.safeHandleRequestsLimitExceeding();
100
+ return {
101
+ result: false,
102
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS
103
+ .REQUESTS_LIMIT_EXCEEDED,
104
+ };
105
+ }
106
+ Logger.log(
107
+ `Retrieved ${result?.coins?.length} supported currencies for swap (withdraw=${withdraw})`,
108
+ loggerSource
109
+ );
110
+ return { result: true, coins: result.coins };
111
+ } catch (e) {
112
+ improveAndRethrow(e, loggerSource);
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Retrieves initial data for swapping two coins.
118
+ *
119
+ * @param fromCoin {Coin}
120
+ * @param toCoin {Coin}
121
+ * @return {Promise<{
122
+ * result: true,
123
+ * min: string,
124
+ * fiatMin: (number|null),
125
+ * max: string,
126
+ * fiatMax: (number|null),
127
+ * rate: (string|null)
128
+ * }|{
129
+ * result: false,
130
+ * reason: string
131
+ * }>}
132
+ */
133
+ async getInitialPublicSwapData(fromCoin, toCoin) {
134
+ try {
135
+ const result = await SwapUtils.getInitialSwapData(
136
+ this._swapProvider,
137
+ fromCoin,
138
+ toCoin
139
+ );
140
+ if (!result.result) {
141
+ if (
142
+ result.reason ===
143
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
144
+ ) {
145
+ SwapUtils.safeHandleRequestsLimitExceeding();
146
+ return {
147
+ result: false,
148
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS
149
+ .REQUESTS_LIMIT_EXCEEDED,
150
+ };
151
+ }
152
+ if (
153
+ result.reason ===
154
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
155
+ ) {
156
+ return {
157
+ result: false,
158
+ reason: PublicSwapService
159
+ .PUBLIC_SWAP_DETAILS_FAIL_REASONS
160
+ .PAIR_NOT_SUPPORTED,
161
+ };
162
+ }
163
+ }
164
+ return result;
165
+ } catch (e) {
166
+ improveAndRethrow(e, "getInitialPublicSwapData");
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Retrieves swap details that can be used to create swap.
172
+ *
173
+ * @param fromCoin {Coin}
174
+ * @param toCoin {Coin}
175
+ * @param fromAmountCoins {string}
176
+ * @param [withoutFiat=false] {boolean} pass true if you don't need the fiat equivalent - this will diminish requests count
177
+ * @return {Promise<{
178
+ * result: false,
179
+ * reason: string,
180
+ * min: (string|null),
181
+ * max: (string|null),
182
+ * rate: (string|undefined),
183
+ * fiatMin: (number|null),
184
+ * fiatMax: (number|null)
185
+ * }|{
186
+ * result: true,
187
+ * swapCreationInfo: BaseSwapCreationInfo
188
+ * }>}
189
+ */
190
+ async getPublicSwapDetails(
191
+ fromCoin,
192
+ toCoin,
193
+ fromAmountCoins,
194
+ withoutFiat = false
195
+ ) {
196
+ const loggerSource = "getPublicSwapDetails";
197
+ try {
198
+ const coinUsdtRate = withoutFiat
199
+ ? null
200
+ : (await this._swapProvider.getCoinToUSDTRate(fromCoin))
201
+ ?.rate ?? null;
202
+ const details = await this._swapProvider.getSwapInfo(
203
+ fromCoin,
204
+ toCoin,
205
+ fromAmountCoins,
206
+ coinUsdtRate
207
+ );
208
+ const min = details.result ? details.min : details.smallestMin;
209
+ const max = details.result ? details.max : details.greatestMax;
210
+ let fiatMin = null,
211
+ fiatMax = null;
212
+ if (coinUsdtRate != null) {
213
+ if (min != null) {
214
+ fiatMin = BigNumber(min)
215
+ .times(coinUsdtRate)
216
+ .toFixed(PublicSwapService._fiatDecimalsCount);
217
+ }
218
+ if (max != null) {
219
+ fiatMax = BigNumber(max)
220
+ .times(coinUsdtRate)
221
+ .toFixed(PublicSwapService._fiatDecimalsCount);
222
+ }
223
+ }
224
+
225
+ const composeFailResult = (reason) => ({
226
+ result: false,
227
+ reason: reason,
228
+ min: min ?? null,
229
+ fiatMin: fiatMin,
230
+ max: max ?? null,
231
+ fiatMax: fiatMax,
232
+ rate: details.rate ?? null,
233
+ });
234
+
235
+ if (!details.result) {
236
+ if (
237
+ details?.reason ===
238
+ SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
239
+ )
240
+ return composeFailResult(
241
+ PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS
242
+ .PAIR_NOT_SUPPORTED
243
+ );
244
+ else if (
245
+ details?.reason ===
246
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
247
+ ) {
248
+ SwapUtils.safeHandleRequestsLimitExceeding();
249
+ return composeFailResult(
250
+ PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS
251
+ .REQUESTS_LIMIT_EXCEEDED
252
+ );
253
+ }
254
+ }
255
+
256
+ const fromAmountBigNumber = BigNumber(fromAmountCoins);
257
+ if (typeof min === "string" && fromAmountBigNumber.lt(min)) {
258
+ return composeFailResult(
259
+ PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS
260
+ .AMOUNT_LESS_THAN_MIN_SWAPPABLE
261
+ );
262
+ } else if (typeof max === "string" && fromAmountBigNumber.gt(max)) {
263
+ return composeFailResult(
264
+ PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS
265
+ .AMOUNT_HIGHER_THAN_MAX_SWAPPABLE
266
+ );
267
+ }
268
+
269
+ const toAmountCoins = AmountUtils.trim(
270
+ fromAmountBigNumber.times(details.rate),
271
+ fromCoin.digits
272
+ );
273
+ const result = {
274
+ result: true,
275
+ swapCreationInfo: new BaseSwapCreationInfo(
276
+ fromCoin,
277
+ toCoin,
278
+ fromAmountCoins,
279
+ toAmountCoins,
280
+ details.rate,
281
+ details.rawSwapData,
282
+ min,
283
+ fiatMin,
284
+ max,
285
+ fiatMax,
286
+ details.durationMinutesRange
287
+ ),
288
+ };
289
+ Logger.log(
290
+ `Result: ${safeStringify({
291
+ result: result.result,
292
+ swapCreationInfo: {
293
+ ...result.swapCreationInfo,
294
+ fromCoin: result?.swapCreationInfo?.fromCoin?.ticker,
295
+ toCoin: result?.swapCreationInfo?.toCoin?.ticker,
296
+ },
297
+ })}`,
298
+ loggerSource
299
+ );
300
+
301
+ return result;
302
+ } catch (e) {
303
+ improveAndRethrow(e, loggerSource);
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Creates swap by given params.
309
+ *
310
+ * @param fromCoin {Coin}
311
+ * @param toCoin {Coin}
312
+ * @param fromAmount {string}
313
+ * @param swapCreationInfo {BaseSwapCreationInfo}
314
+ * @param toAddress {string}
315
+ * @param refundAddress {string}
316
+ * @param clientIp {string}
317
+ * @param [toCurrencyExtraId] {string}
318
+ * @param [refundExtraId] {string}
319
+ * @return {Promise<{
320
+ * result: true,
321
+ * fiatCurrencyCode: string,
322
+ * toCoin: Coin,
323
+ * fromAmountFiat: (number|null),
324
+ * address: string,
325
+ * durationMinutesRange: string,
326
+ * fromAmount: string,
327
+ * toAmount: string,
328
+ * toAmountFiat: (number|null),
329
+ * fiatCurrencyDecimals: number,
330
+ * fromCoin: Coin,
331
+ * rate: string,
332
+ * swapId: string,
333
+ * fromCurrencyExtraId: string
334
+ * }|{
335
+ * result: false,
336
+ * reason: string
337
+ * }>}
338
+ */
339
+ async createPublicSwap(
340
+ fromCoin,
341
+ toCoin,
342
+ fromAmount,
343
+ swapCreationInfo,
344
+ toAddress,
345
+ refundAddress,
346
+ clientIp,
347
+ toCurrencyExtraId,
348
+ refundExtraId
349
+ ) {
350
+ const loggerSource = "createPublicSwap";
351
+ try {
352
+ if (
353
+ !(fromCoin instanceof Coin) ||
354
+ !(toCoin instanceof Coin) ||
355
+ typeof fromAmount !== "string" ||
356
+ typeof toAddress !== "string" ||
357
+ typeof refundAddress !== "string" ||
358
+ !(swapCreationInfo instanceof BaseSwapCreationInfo)
359
+ ) {
360
+ throw new Error(
361
+ `Wrong input: ${fromCoin.ticker} ${toCoin.ticker} ${fromAmount} ${swapCreationInfo}`
362
+ );
363
+ }
364
+ Logger.log(
365
+ `Start: ${fromAmount} ${fromCoin.ticker} -> ${
366
+ toCoin.ticker
367
+ }. Details: ${safeStringify({
368
+ ...swapCreationInfo,
369
+ fromCoin: swapCreationInfo?.fromCoin?.ticker,
370
+ toCoin: swapCreationInfo?.toCoin?.ticker,
371
+ })}`,
372
+ loggerSource
373
+ );
374
+
375
+ const result = await this._swapProvider.createSwap(
376
+ fromCoin,
377
+ toCoin,
378
+ fromAmount,
379
+ toAddress,
380
+ refundAddress,
381
+ swapCreationInfo.rawSwapData,
382
+ clientIp,
383
+ toCurrencyExtraId,
384
+ refundExtraId
385
+ );
386
+ Logger.log(
387
+ `Created:${safeStringify({
388
+ ...result,
389
+ fromCoin: fromCoin?.ticker,
390
+ toCoin: toCoin?.ticker,
391
+ })}`,
392
+ loggerSource
393
+ );
394
+ if (!result?.result) {
395
+ if (
396
+ result?.reason ===
397
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
398
+ ) {
399
+ SwapUtils.safeHandleRequestsLimitExceeding();
400
+ return {
401
+ result: false,
402
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS
403
+ .REQUESTS_LIMIT_EXCEEDED,
404
+ };
405
+ }
406
+ if (
407
+ result?.reason ===
408
+ SwapProvider.CREATION_FAIL_REASONS.RETRIABLE_FAIL
409
+ ) {
410
+ // TODO: [feature, high] implement retrying if one partner fail and we have another partners task_id=a07e367e488f4a4899613ac9056fa359
411
+ // return {
412
+ // result: false,
413
+ // reason: PublicSwapService.SWAP_CREATION_FAIL_REASONS.RETRIABLE_FAIL,
414
+ // };
415
+ }
416
+ }
417
+ if (result.result && result?.swapId) {
418
+ let fromAmountFiat = null,
419
+ toAmountFiat = null;
420
+ try {
421
+ const fromCoinUsdtRate =
422
+ (await this._swapProvider.getCoinToUSDTRate(fromCoin))
423
+ ?.rate ?? null;
424
+ const toCoinUsdtRate =
425
+ (await this._swapProvider.getCoinToUSDTRate(fromCoin))
426
+ ?.rate ?? null;
427
+ if (fromCoinUsdtRate != null && result.fromAmount != null) {
428
+ fromAmountFiat = BigNumber(result.fromAmount)
429
+ .times(fromCoinUsdtRate)
430
+ .toFixed(PublicSwapService._fiatDecimalsCount);
431
+ }
432
+ if (toCoinUsdtRate != null && result.toAmount != null) {
433
+ toAmountFiat = BigNumber(result.toAmount)
434
+ .times(toCoinUsdtRate)
435
+ .toFixed(PublicSwapService._fiatDecimalsCount);
436
+ }
437
+ } catch (e) {
438
+ Logger.logError(
439
+ e,
440
+ loggerSource,
441
+ "Failed to calculate fiat amounts for result"
442
+ );
443
+ }
444
+
445
+ EventBusInstance.dispatch(
446
+ PublicSwapService.PUBLIC_SWAP_CREATED_EVENT,
447
+ null,
448
+ fromCoin.ticker,
449
+ toCoin.ticker,
450
+ fromAmountFiat
451
+ );
452
+
453
+ const toReturn = {
454
+ result: true,
455
+ swapId: result.swapId,
456
+ fromCoin: fromCoin,
457
+ toCoin: toCoin,
458
+ fromAmount: result.fromAmount,
459
+ toAmount: result.toAmount,
460
+ fromAmountFiat: fromAmountFiat,
461
+ toAmountFiat: toAmountFiat,
462
+ fiatCurrencyCode: "USD",
463
+ fiatCurrencyDecimals: PublicSwapService._fiatDecimalsCount,
464
+ rate: result.rate,
465
+ durationMinutesRange: swapCreationInfo.durationMinutesRange,
466
+ address: result.fromAddress, // CRITICAL: this is the address to send coins to swaps provider
467
+ fromCurrencyExtraId: result.fromCurrencyExtraId ?? "", // CRITICAL: this is the extra ID for address to send coins to swaps provider
468
+ };
469
+
470
+ this._savePublicSwapIdLocally(result.swapId);
471
+
472
+ Logger.log(
473
+ `Returning: ${safeStringify({
474
+ ...toReturn,
475
+ fromCoin: fromCoin?.ticker,
476
+ toCoin: toCoin?.ticker,
477
+ })}`,
478
+ loggerSource
479
+ );
480
+ return toReturn;
481
+ }
482
+
483
+ throw new Error(
484
+ `Unexpected result from provider ${safeStringify(result)}`
485
+ );
486
+ } catch (e) {
487
+ improveAndRethrow(e, loggerSource);
488
+ }
489
+ }
490
+
491
+ /**
492
+ * Retrieves swap details and status for existing swaps by their ids.
493
+ *
494
+ * @param swapIds {string[]}
495
+ * @return {Promise<{
496
+ * result: true,
497
+ * swaps: ExistingSwapWithFiatData[]
498
+ * }|{
499
+ * result: false,
500
+ * reason: string
501
+ * }>}
502
+ * error reason is one of PUBLIC_SWAPS_COMMON_ERRORS
503
+ */
504
+ async getPublicExistingSwapDetailsAndStatus(swapIds) {
505
+ const loggerSource = "getPublicExistingSwapDetailsAndStatus";
506
+ try {
507
+ const result =
508
+ await SwapUtils.getExistingSwapsDetailsWithFiatAmounts(
509
+ this._swapProvider,
510
+ swapIds
511
+ );
512
+ if (!result?.result) {
513
+ if (
514
+ result.reason ===
515
+ SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
516
+ ) {
517
+ SwapUtils.safeHandleRequestsLimitExceeding();
518
+ return {
519
+ result: false,
520
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS
521
+ .REQUESTS_LIMIT_EXCEEDED,
522
+ };
523
+ }
524
+ throw new Error("Unknown reason: " + result?.reason);
525
+ }
526
+
527
+ return result;
528
+ } catch (e) {
529
+ improveAndRethrow(e, loggerSource);
530
+ }
531
+ }
532
+
533
+ /**
534
+ * Retrieves the whole available swaps history by ids saved locally.
535
+ *
536
+ * @return {Promise<{
537
+ * result: true,
538
+ * swaps: ExistingSwapWithFiatData[]
539
+ * }|{
540
+ * result: false,
541
+ * reason: string
542
+ * }>}
543
+ */
544
+ async getPublicSwapsHistory() {
545
+ try {
546
+ const swapIds = this._getPublicSwapIdsSavedLocally();
547
+ if (swapIds.length) {
548
+ return await this.getPublicExistingSwapDetailsAndStatus(
549
+ swapIds
550
+ );
551
+ }
552
+ return { result: true, swaps: [] };
553
+ } catch (e) {
554
+ improveAndRethrow(e, "getPublicSwapsHistory");
555
+ }
556
+ }
557
+
558
+ /**
559
+ * @param swapId {string}
560
+ * @private
561
+ */
562
+ _savePublicSwapIdLocally(swapId) {
563
+ if (typeof window !== "undefined") {
564
+ try {
565
+ const saved = localStorage.getItem("publicSwapIds");
566
+ const ids =
567
+ typeof saved === "string" && saved.length > 0
568
+ ? saved.split(",")
569
+ : [];
570
+ ids.push(swapId);
571
+ localStorage.setItem("publicSwapIds", ids.join(","));
572
+ } catch (e) {
573
+ improveAndRethrow(e, "_savePublicSwapIdLocally");
574
+ }
575
+ }
576
+ }
577
+
578
+ /**
579
+ * @private
580
+ * @return {string[]}
581
+ */
582
+ _getPublicSwapIdsSavedLocally() {
583
+ if (typeof window !== "undefined") {
584
+ try {
585
+ const saved = localStorage.getItem("publicSwapIds");
586
+ return typeof saved === "string" && saved.length > 0
587
+ ? saved.split(",")
588
+ : [];
589
+ } catch (e) {
590
+ improveAndRethrow(e, "_getPublicSwapIdsSavedLocally");
591
+ }
592
+ }
593
+ }
594
+
595
+ /**
596
+ * @param coinOrTicker {Coin|string}
597
+ * @return {string} icon URL (ready to use)
598
+ */
599
+ getAssetIconUrl(coinOrTicker) {
600
+ return this._swapProvider.getIconUrl(coinOrTicker);
601
+ }
602
+
603
+ /**
604
+ * @param ticker {string}
605
+ * @return {Coin|null}
606
+ */
607
+ getCoinByTickerIfPresent(ticker) {
608
+ return this._swapProvider.getCoinByTickerIfPresent(ticker);
609
+ }
610
+
611
+ /**
612
+ * TODO: [feature, moderate] add other fiat currencies support. task_id=5490e21b8b9c4f89a2247b28db3c9e0a
613
+ * @param asset {Coin}
614
+ * @return {Promise<string|null>}
615
+ */
616
+ async getAssetToUsdtRate(asset) {
617
+ try {
618
+ const result = await this._swapProvider.getCoinToUSDTRate(asset);
619
+ return result?.rate ?? null;
620
+ } catch (e) {
621
+ improveAndRethrow(e, "getAssetToUsdtRate");
622
+ }
623
+ }
624
+
625
+ /**
626
+ * @param asset {Coin}
627
+ * @param address {string}
628
+ * @return {boolean}
629
+ */
630
+ isAddressValidForAsset(asset, address) {
631
+ try {
632
+ return this._swapProvider.isAddressValidForAsset(asset, address);
633
+ } catch (e) {
634
+ improveAndRethrow(e, "isAddressValidForAsset");
635
+ }
636
+ }
637
+
638
+ /**
639
+ * Retrieves token by contract address.
640
+ *
641
+ * @param addressString {string}
642
+ * @return {Promise<Coin|null>}
643
+ */
644
+ async getTokenByContractAddress(addressString) {
645
+ try {
646
+ if (!addressString) return null;
647
+ const addressLowerCase = addressString.toLowerCase();
648
+ const allCoins =
649
+ await this._swapProvider.getAllSupportedCurrencies();
650
+ if (allCoins.result) {
651
+ return allCoins.coins.find(
652
+ (coin) =>
653
+ coin.tokenAddress &&
654
+ coin.tokenAddress.toLowerCase() === addressLowerCase
655
+ );
656
+ }
657
+ } catch (e) {
658
+ Logger.logError(e, "getTokenByContractAddress");
659
+ }
660
+ return null;
661
+ }
662
+
663
+ /**
664
+ * @param asset {Coin}
665
+ * @return {string|null}
666
+ */
667
+ getExtraIdNameIfPresentForAsset(asset) {
668
+ try {
669
+ return this._swapProvider.getExtraIdNameIfPresent(asset);
670
+ } catch (e) {
671
+ improveAndRethrow(e, "getExtraIdNameIfPresentForAsset");
672
+ }
673
+ }
674
+ }