@rabbitio/ui-kit 1.0.0-beta.11 → 1.0.0-beta.13

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.
@@ -1,5 +1,6 @@
1
1
  import React, { useState, useRef, useEffect } from 'react';
2
2
  import { BigNumber } from 'bignumber.js';
3
+ import axios from 'axios';
3
4
 
4
5
  function createCommonjsModule(fn) {
5
6
  var module = { exports: {} };
@@ -2311,6 +2312,21 @@ class Cache {
2311
2312
  }
2312
2313
  }
2313
2314
 
2315
+ class EmailsApi {
2316
+ static async sendEmail(subject, body) {
2317
+ try {
2318
+ const url = `${window.location.protocol + "//" + window.location.host}/api/v1/${this.serverEndpointEntity}`;
2319
+ await axios.post(url, {
2320
+ subject,
2321
+ body
2322
+ });
2323
+ } catch (e) {
2324
+ improveAndRethrow(e, "sendEmail", subject + body);
2325
+ }
2326
+ }
2327
+ }
2328
+ EmailsApi.serverEndpointEntity = "emails";
2329
+
2314
2330
  class ExistingSwap {
2315
2331
  /**
2316
2332
  * @param swapId {string}
@@ -2353,6 +2369,78 @@ class ExistingSwap {
2353
2369
  }
2354
2370
  }
2355
2371
 
2372
+ class ExistingSwapWithFiatData extends ExistingSwap {
2373
+ /**
2374
+ * @param swapId {string}
2375
+ * @param status {SwapProvider.SWAP_STATUSES}
2376
+ * @param createdAt {number}
2377
+ * @param expiresAt {number}
2378
+ * @param confirmations {number}
2379
+ * @param rate {string}
2380
+ * @param refundAddress {string}
2381
+ * @param fromCoin {Coin}
2382
+ * @param fromAmount {string}
2383
+ * @param fromTransactionId {string}
2384
+ * @param toCoin {Coin}
2385
+ * @param toAmount {string}
2386
+ * @param toTransactionId {string|null}
2387
+ * @param toAddress {string}
2388
+ * @param partner {string}
2389
+ * @param fromAmountFiat {number}
2390
+ * @param toAmountFiat {number}
2391
+ * @param fiatCurrencyCode {string}
2392
+ * @param fiatCurrencyDecimals {number}
2393
+ */
2394
+ constructor(swapId, status, createdAt, expiresAt, confirmations, rate, refundAddress, payToAddress, fromCoin, fromAmount, fromTransactionId, fromTransactionLink, toCoin, toAmount, toTransactionId, toTransactionLink, toAddress, partner, fromAmountFiat, toAmountFiat, fiatCurrencyCode, fiatCurrencyDecimals) {
2395
+ super(swapId, status, createdAt, expiresAt, confirmations, rate, refundAddress, payToAddress, fromCoin, fromAmount, fromTransactionId, fromTransactionLink, toCoin, toAmount, toTransactionId, toTransactionLink, toAddress, partner);
2396
+ this.fromAmountFiat = fromAmountFiat;
2397
+ this.toAmountFiat = toAmountFiat;
2398
+ this.fiatCurrencyCode = fiatCurrencyCode;
2399
+ this.fiatCurrencyDecimals = fiatCurrencyDecimals;
2400
+ }
2401
+
2402
+ /**
2403
+ * @param existingSwap {ExistingSwap}
2404
+ * @param fromAmountFiat {number}
2405
+ * @param toAmountFiat {number}
2406
+ * @param fiatCurrencyCode {string}
2407
+ * @param fiatCurrencyDecimals {number}
2408
+ * @return {ExistingSwapWithFiatData}
2409
+ */
2410
+ static fromExistingSwap(existingSwap, fromAmountFiat, toAmountFiat, fiatCurrencyCode, fiatCurrencyDecimals) {
2411
+ return new ExistingSwapWithFiatData(existingSwap.swapId, existingSwap.status, existingSwap.createdAt, existingSwap.expiresAt, existingSwap.confirmations, existingSwap.rate, existingSwap.refundAddress, existingSwap.payToAddress, existingSwap.fromCoin, existingSwap.fromAmount, existingSwap.fromTransactionId, existingSwap.fromTransactionLink, existingSwap.toCoin, existingSwap.toAmount, existingSwap.toTransactionId, existingSwap.toTransactionLink, existingSwap.toAddress, existingSwap.partner, fromAmountFiat, toAmountFiat, fiatCurrencyCode, fiatCurrencyDecimals);
2412
+ }
2413
+ }
2414
+
2415
+ class PublicSwapCreationInfo {
2416
+ /**
2417
+ * @param fromCoin {Coin}
2418
+ * @param toCoin {Coin}
2419
+ * @param fromAmountCoins {string}
2420
+ * @param toAmountCoins {string}
2421
+ * @param rate {string}
2422
+ * @param rawSwapData {Object}
2423
+ * @param min {string}
2424
+ * @param fiatMin {number}
2425
+ * @param max {string}
2426
+ * @param fiatMax {number}
2427
+ * @param durationMinutesRange {string}
2428
+ */
2429
+ constructor(fromCoin, toCoin, fromAmountCoins, toAmountCoins, rate, rawSwapData, min, fiatMin, max, fiatMax, durationMinutesRange) {
2430
+ this.fromCoin = fromCoin;
2431
+ this.toCoin = toCoin;
2432
+ this.fromAmountCoins = fromAmountCoins;
2433
+ this.toAmountCoins = toAmountCoins;
2434
+ this.rate = rate;
2435
+ this.rawSwapData = rawSwapData;
2436
+ this.min = min;
2437
+ this.fiatMin = fiatMin;
2438
+ this.max = max;
2439
+ this.fiatMax = fiatMax;
2440
+ this.durationMinutesRange = durationMinutesRange;
2441
+ }
2442
+ }
2443
+
2356
2444
  class SwapProvider {
2357
2445
  /**
2358
2446
  * @return {Promise<void>}
@@ -2525,5 +2613,477 @@ SwapProvider.SWAP_STATUSES = {
2525
2613
  FAILED: "failed" // public +
2526
2614
  };
2527
2615
 
2528
- export { AmountUtils, AssetIcon, Blockchain, Button, Cache, Coin, ExistingSwap, FiatCurrenciesService, LoadingDots, Logger, LogsStorage, Protocol, SupportChat, SwapProvider, improveAndRethrow, safeStringify };
2616
+ const BANNED_PARTNERS = ["stealthex", "changee", "coincraddle"];
2617
+ const FALLBACK_ICON_URL = "https://rabbit.io/asset-icons/fallback.svg";
2618
+ class SwapspaceSwapProvider extends SwapProvider {
2619
+ constructor(apiKeysProxyUrl, cache, customCoinBuilder = (coin, network) => null, useRestrictedCoinsSet = true) {
2620
+ super();
2621
+ this._supportedCoins = [];
2622
+ this._URL = `${apiKeysProxyUrl}/swapspace`;
2623
+ this._maxRateDigits = 20;
2624
+ this.useRestrictedCoinsSet = useRestrictedCoinsSet;
2625
+ this._customCoinBuilder = customCoinBuilder;
2626
+ this._cache = cache;
2627
+ }
2628
+ getSwapCreationInfoTtlMs() {
2629
+ /* Actually 2 minutes and only relevant for some partners, but we use it
2630
+ * (and even a bit smaller value) for better consistency */
2631
+ return 110000;
2632
+ }
2633
+ async getDepositCurrencies() {
2634
+ const loggerSource = "getDepositCurrencies";
2635
+ try {
2636
+ var _this$_supportedCoins;
2637
+ await this._fetchSupportedCurrenciesIfNeeded();
2638
+ Logger.log(`We have ${(_this$_supportedCoins = this._supportedCoins) == null ? void 0 : _this$_supportedCoins.length} supported coins, getting depositable`, loggerSource);
2639
+ return {
2640
+ result: true,
2641
+ coins: this._supportedCoins.filter(item => item.deposit).map(item => item.coin)
2642
+ };
2643
+ } catch (e) {
2644
+ var _e$response;
2645
+ if ((e == null || (_e$response = e.response) == null ? void 0 : _e$response.status) === 429) {
2646
+ return {
2647
+ result: false,
2648
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
2649
+ };
2650
+ }
2651
+ improveAndRethrow(e, loggerSource);
2652
+ }
2653
+ }
2654
+ async getWithdrawalCurrencies(exceptCurrency = null) {
2655
+ const loggerSource = "getWithdrawalCurrencies";
2656
+ try {
2657
+ var _this$_supportedCoins2;
2658
+ await this._fetchSupportedCurrenciesIfNeeded();
2659
+ Logger.log(`We have ${(_this$_supportedCoins2 = this._supportedCoins) == null ? void 0 : _this$_supportedCoins2.length} supported coins, getting withdrawable`, loggerSource);
2660
+ return {
2661
+ result: true,
2662
+ coins: this._supportedCoins.filter(item => item.withdrawal && (!exceptCurrency || item.coin !== exceptCurrency)).map(item => item.coin)
2663
+ };
2664
+ } catch (e) {
2665
+ var _e$response2;
2666
+ if ((e == null || (_e$response2 = e.response) == null ? void 0 : _e$response2.status) === 429) {
2667
+ return {
2668
+ result: false,
2669
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
2670
+ };
2671
+ }
2672
+ improveAndRethrow(e, loggerSource);
2673
+ }
2674
+ }
2675
+ async initialize() {
2676
+ await this._fetchSupportedCurrenciesIfNeeded();
2677
+ }
2678
+ getIconUrl(coinOrTicker) {
2679
+ const loggerSource = "getIconUrl";
2680
+ try {
2681
+ var _this$_supportedCoins4, _this$_supportedCoins5;
2682
+ let coin = coinOrTicker;
2683
+ if (!(coinOrTicker instanceof Coin)) {
2684
+ var _this$_supportedCoins3;
2685
+ coin = (_this$_supportedCoins3 = this._supportedCoins.find(i => i.coin.ticker === coinOrTicker)) == null ? void 0 : _this$_supportedCoins3.coin;
2686
+ }
2687
+ return (_this$_supportedCoins4 = (_this$_supportedCoins5 = this._supportedCoins.find(item => item.coin === coin)) == null ? void 0 : _this$_supportedCoins5.iconURL) != null ? _this$_supportedCoins4 : FALLBACK_ICON_URL;
2688
+ } catch (e) {
2689
+ improveAndRethrow(e, loggerSource);
2690
+ }
2691
+ }
2692
+ async _fetchSupportedCurrenciesIfNeeded() {
2693
+ const loggerSource = "_fetchSupportedCurrenciesIfNeeded";
2694
+ try {
2695
+ var _this$_supportedCoins6;
2696
+ if (!((_this$_supportedCoins6 = this._supportedCoins) != null && _this$_supportedCoins6.length)) {
2697
+ var _rawResponse$data, _rawResponse$data2;
2698
+ const rawResponse = await axios.get(`${this._URL}/api/v2/currencies`);
2699
+ Logger.log(`Retrieved ${rawResponse == null || (_rawResponse$data = rawResponse.data) == null ? void 0 : _rawResponse$data.length} currencies`, loggerSource);
2700
+ this._supportedCoins = ((_rawResponse$data2 = rawResponse == null ? void 0 : rawResponse.data) != null ? _rawResponse$data2 : []).map(item => {
2701
+ let coin = this._customCoinBuilder(item.code, item.network);
2702
+ if (!coin && !this.useRestrictedCoinsSet) {
2703
+ /** Building coin object for coin that isn't supported OOB in Rabbit.
2704
+ * We are doing this way to be able to use extended coins set for swaps.
2705
+ * These temporary built coins are only for in-swap use, and we omit some usual
2706
+ * coin details here.
2707
+ * Ideally we should add some new abstractions e.g. BaseCoin:
2708
+ * Coin will extend BaseCoin, SwapCoin will extend BaseCoin etc.
2709
+ * But for now it is reasonable to use this simpler approach.
2710
+ */
2711
+ const code = item.code.toUpperCase();
2712
+ const network = item.network.toUpperCase();
2713
+ const ticker = `${code}${code === network ? "" : network}`;
2714
+ const defaultDecimalPlacesForCoinNotSupportedOOB = 8;
2715
+ const defaultMinConfirmationsForCoinNotSupportedOOB = 1;
2716
+ coin = new Coin(item.name, ticker, code, defaultDecimalPlacesForCoinNotSupportedOOB, null, "", null, null, defaultMinConfirmationsForCoinNotSupportedOOB, null, [], 60000, null,
2717
+ // We cannot recognize blockchain from swapspace data
2718
+ new Protocol(network),
2719
+ // TODO: [dev] maybe we should recognize standard protocols?
2720
+ item.contractAddress || null, false);
2721
+ }
2722
+ if (coin) {
2723
+ var _item$deposit, _item$withdrawal, _item$validationRegex;
2724
+ return {
2725
+ coin: coin,
2726
+ code: item.code,
2727
+ network: item.network,
2728
+ extraId: item.extraIdName,
2729
+ isPopular: !!(item != null && item.popular),
2730
+ iconURL: item.icon ? `https://storage.swapspace.co${item.icon}` : FALLBACK_ICON_URL,
2731
+ deposit: (_item$deposit = item.deposit) != null ? _item$deposit : false,
2732
+ withdrawal: (_item$withdrawal = item.withdrawal) != null ? _item$withdrawal : false,
2733
+ validationRegexp: (_item$validationRegex = item.validationRegexp) != null ? _item$validationRegex : null
2734
+ };
2735
+ }
2736
+ return [];
2737
+ }).flat();
2738
+ this._putPopularCoinsFirst();
2739
+ }
2740
+ } catch (e) {
2741
+ improveAndRethrow(e, loggerSource);
2742
+ }
2743
+ }
2744
+
2745
+ /**
2746
+ * This method sort internal list putting popular (as swapspace thinks) coins to the top.
2747
+ * This is just for users of this API if they don't care about the sorting - we just improve a list a bit this way.
2748
+ * @private
2749
+ */
2750
+ _putPopularCoinsFirst() {
2751
+ this._supportedCoins.sort((i1, i2) => {
2752
+ if (i1.isPopular && !i2.isPopular) return -1;
2753
+ if (i2.isPopular && !i1.isPopular) return 1;
2754
+ return i1.coin.ticker > i2.coin.ticker ? 1 : i1.coin.ticker < i2.coin.ticker ? -1 : 0;
2755
+ });
2756
+ }
2757
+ async getCoinToUSDTRate(coin) {
2758
+ const loggerSource = "getCoinToUSDTRate";
2759
+ try {
2760
+ var _this$_supportedCoins7;
2761
+ await this._fetchSupportedCurrenciesIfNeeded();
2762
+
2763
+ // Using USDT TRC20 as usually fee in this network is smaller than ERC20 and this network is widely used for USDT
2764
+ const usdtTrc20 = (_this$_supportedCoins7 = this._supportedCoins.find(i => i.code === "usdt" && i.network === "trc20")) == null ? void 0 : _this$_supportedCoins7.coin;
2765
+ if (!usdtTrc20) {
2766
+ return {
2767
+ result: false
2768
+ };
2769
+ }
2770
+ const cached = this._cache.get("swapspace_usdt_rate_" + coin.ticker);
2771
+ if (cached != null) {
2772
+ return {
2773
+ result: true,
2774
+ rate: cached
2775
+ };
2776
+ }
2777
+ Logger.log("Loading USDT -> coin rate as not found in cache:", coin == null ? void 0 : coin.ticker);
2778
+ const result = await this.getSwapInfo(usdtTrc20, coin, "5000");
2779
+ if (!result.result) {
2780
+ return {
2781
+ result: false
2782
+ };
2783
+ }
2784
+
2785
+ // This calculation is not precise as we cannot recognize the actual fee and network fee. Just approximate.
2786
+ const standardSwapspaceFeeMultiplier = 1.002; // usually 0.2%
2787
+ const rate = BigNumber(1).div(BigNumber(result.rate).times(standardSwapspaceFeeMultiplier)).toString();
2788
+ this._cache.put("swapspace_usdt_rate_" + coin.ticker, rate, 15 * 60000);
2789
+ return {
2790
+ result: true,
2791
+ rate: rate
2792
+ };
2793
+ } catch (e) {
2794
+ improveAndRethrow(e, loggerSource);
2795
+ }
2796
+ }
2797
+ getCoinByTickerIfPresent(ticker) {
2798
+ try {
2799
+ var _item$coin;
2800
+ const item = this._supportedCoins.find(i => i.coin.ticker === ticker);
2801
+ return (_item$coin = item == null ? void 0 : item.coin) != null ? _item$coin : null;
2802
+ } catch (e) {
2803
+ improveAndRethrow(e, "getCoinByTickerIfPresent");
2804
+ }
2805
+ }
2806
+ async getSwapInfo(fromCoin, toCoin, amountCoins, fromCoinToUsdRate = null) {
2807
+ const loggerSource = "getSwapInfo";
2808
+ try {
2809
+ var _response$data;
2810
+ if (!(fromCoin instanceof Coin) || !(toCoin instanceof Coin) || typeof amountCoins !== "string" || BigNumber(amountCoins).lt("0")) {
2811
+ throw new Error(`Wrong input params: ${amountCoins} ${fromCoin.ticker} -> ${toCoin.ticker}` + (fromCoin instanceof Coin) + (toCoin instanceof Coin));
2812
+ }
2813
+ const fromCoinSwapspaceDetails = this._supportedCoins.find(i => i.coin === fromCoin);
2814
+ const toCoinSwapspaceDetails = this._supportedCoins.find(i => i.coin === toCoin);
2815
+ if (!fromCoinSwapspaceDetails || !toCoinSwapspaceDetails) {
2816
+ throw new Error("Failed to find swapspace coin details for: " + fromCoin.ticker + " -> " + toCoin.ticker);
2817
+ }
2818
+ /* Here we use not documented parameter 'estimated=false'. This parameter controls whether we want to use
2819
+ * cached rate values stored in swapspace cache. Their support says they store at most for 30 sec.
2820
+ * But we are better off using the most actual rates.
2821
+ */
2822
+ const response = await axios.get(`${this._URL}/api/v2/amounts?fromCurrency=${fromCoinSwapspaceDetails.code}&fromNetwork=${fromCoinSwapspaceDetails.network}&toNetwork=${toCoinSwapspaceDetails.network}&toCurrency=${toCoinSwapspaceDetails.code}&amount=${amountCoins}&float=true&estimated=false`);
2823
+ Logger.log(`Retrieved ${response == null || (_response$data = response.data) == null ? void 0 : _response$data.length} options`, loggerSource);
2824
+ const options = Array.isArray(response.data) ? response.data : [];
2825
+ const exchangesSupportingThePair = options.filter(exchange => (exchange == null ? void 0 : exchange.exists) && !BANNED_PARTNERS.find(bannedPartner => bannedPartner === (exchange == null ? void 0 : exchange.partner)) && (exchange == null ? void 0 : exchange.fixed) === false && (exchange.min === 0 || exchange.max === 0 || exchange.max > exchange.min || (typeof exchange.min !== "number" || typeof exchange.max !== "number") && exchange.toAmount > 0));
2826
+ Logger.log(`${exchangesSupportingThePair == null ? void 0 : exchangesSupportingThePair.length} of them have exist=true`, loggerSource);
2827
+ if (!exchangesSupportingThePair.length) {
2828
+ return {
2829
+ result: false,
2830
+ reason: SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
2831
+ };
2832
+ }
2833
+ const availableExchanges = exchangesSupportingThePair.filter(exchange => typeof (exchange == null ? void 0 : exchange.toAmount) === "number" && exchange.toAmount > 0);
2834
+ Logger.log(`Available (having amountTo): ${safeStringify(availableExchanges)}`, loggerSource);
2835
+ // min=0 or max=0 means there is no limit for the partner
2836
+ let smallestMin = null;
2837
+ if (exchangesSupportingThePair.find(ex => BigNumber(ex.min).isZero()) == null) {
2838
+ smallestMin = exchangesSupportingThePair.reduce((prev, cur) => {
2839
+ if (typeof cur.min === "number" && (prev === null || BigNumber(cur.min).lt(prev))) return BigNumber(cur.min);
2840
+ return prev;
2841
+ }, null);
2842
+ }
2843
+ let greatestMax = null;
2844
+ if (exchangesSupportingThePair.find(ex => BigNumber(ex.max).isZero()) == null) {
2845
+ greatestMax = exchangesSupportingThePair.reduce((prev, cur) => {
2846
+ if (typeof cur.max === "number" && (prev === null || BigNumber(cur.max).gt(prev))) return BigNumber(cur.max);
2847
+ return prev;
2848
+ }, null);
2849
+ }
2850
+ let extraCoinsToFitMinMax = "0";
2851
+ if (typeof fromCoinToUsdRate === "string" && BigNumber(fromCoinToUsdRate).gt("0")) {
2852
+ const extraUsdToFitMinMax = BigNumber("1"); // We correct the limits as the exact limit can fluctuate and cause failed swap creation
2853
+ extraCoinsToFitMinMax = AmountUtils.trim(extraUsdToFitMinMax.div(fromCoinToUsdRate), fromCoin.digits);
2854
+ }
2855
+ if (smallestMin instanceof BigNumber) {
2856
+ smallestMin = AmountUtils.trim(smallestMin.plus(extraCoinsToFitMinMax), fromCoin.digits);
2857
+ }
2858
+ if (greatestMax instanceof BigNumber) {
2859
+ if (greatestMax > extraCoinsToFitMinMax) {
2860
+ greatestMax = AmountUtils.trim(greatestMax.minus(extraCoinsToFitMinMax), fromCoin.digits);
2861
+ } else {
2862
+ greatestMax = "0";
2863
+ }
2864
+ }
2865
+ if (availableExchanges.length) {
2866
+ var _bestOpt$duration;
2867
+ const sorted = availableExchanges.sort((op1, op2) => op2.toAmount - op1.toAmount);
2868
+ const bestOpt = sorted[0];
2869
+ Logger.log(`Returning first option after sorting: ${safeStringify(bestOpt)}`, loggerSource);
2870
+ let max = null;
2871
+ let min = null;
2872
+ if (extraCoinsToFitMinMax != null) {
2873
+ if (typeof bestOpt.max === "number" && bestOpt.max !== 0) {
2874
+ max = BigNumber(bestOpt.max).minus(extraCoinsToFitMinMax);
2875
+ max = AmountUtils.trim(max.lt(0) ? "0" : max, fromCoin.digits);
2876
+ }
2877
+ if (typeof bestOpt.min === "number" && bestOpt.min !== 0) {
2878
+ min = AmountUtils.trim(BigNumber(bestOpt.min).plus(extraCoinsToFitMinMax), fromCoin.digits);
2879
+ }
2880
+ }
2881
+ const rate = bestOpt.toAmount && bestOpt.fromAmount ? BigNumber(bestOpt.toAmount).div(bestOpt.fromAmount) : null;
2882
+ return {
2883
+ result: true,
2884
+ min: min,
2885
+ max: max,
2886
+ smallestMin: smallestMin,
2887
+ greatestMax: greatestMax,
2888
+ rate: rate != null ? AmountUtils.trim(rate, this._maxRateDigits) : null,
2889
+ durationMinutesRange: (_bestOpt$duration = bestOpt.duration) != null ? _bestOpt$duration : null,
2890
+ rawSwapData: bestOpt
2891
+ };
2892
+ }
2893
+ const result = {
2894
+ result: false,
2895
+ reason: smallestMin && BigNumber(amountCoins).lt(smallestMin) ? SwapProvider.NO_SWAPS_REASONS.TOO_LOW : greatestMax && BigNumber(amountCoins).gt(greatestMax) ? SwapProvider.NO_SWAPS_REASONS.TOO_HIGH : SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED,
2896
+ smallestMin: smallestMin,
2897
+ greatestMax: greatestMax
2898
+ };
2899
+ Logger.log(`Returning result ${safeStringify(result)}`, loggerSource);
2900
+ return result;
2901
+ } catch (e) {
2902
+ var _e$response3;
2903
+ if ((e == null || (_e$response3 = e.response) == null ? void 0 : _e$response3.status) === 429) {
2904
+ return {
2905
+ result: false,
2906
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
2907
+ };
2908
+ }
2909
+ Logger.log(`Internal swapspace/rabbit error when getting swap options ${safeStringify(e)}`, loggerSource);
2910
+ improveAndRethrow(e, loggerSource);
2911
+ }
2912
+ }
2913
+ async createSwap(fromCoin, toCoin, amount, toAddress, refundAddress, rawSwapData, clientIpAddress) {
2914
+ const loggerSource = "createSwap";
2915
+ const partner = rawSwapData == null ? void 0 : rawSwapData.partner;
2916
+ try {
2917
+ var _this$_supportedCoins8, _this$_supportedCoins9;
2918
+ if (!(fromCoin instanceof Coin) || !(toCoin instanceof Coin) || typeof amount !== "string" || typeof toAddress !== "string" || typeof refundAddress !== "string") {
2919
+ throw new Error(`Invalid input: ${fromCoin} ${toCoin} ${amount} ${toAddress} ${refundAddress}`);
2920
+ }
2921
+ if (typeof partner !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.fromCurrency) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.fromNetwork) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.toCurrency) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.toNetwork) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.id) !== "string" // can be just empty
2922
+ ) {
2923
+ throw new Error(`Invalid raw swap data: ${safeStringify(rawSwapData)}`);
2924
+ }
2925
+ await this._fetchSupportedCurrenciesIfNeeded();
2926
+ const toCurrencyExtraId = (_this$_supportedCoins8 = (_this$_supportedCoins9 = this._supportedCoins.find(item => item.coin === toCoin)) == null ? void 0 : _this$_supportedCoins9.extraId) != null ? _this$_supportedCoins8 : "";
2927
+ const requestData = {
2928
+ partner: partner,
2929
+ fromCurrency: rawSwapData == null ? void 0 : rawSwapData.fromCurrency,
2930
+ fromNetwork: rawSwapData == null ? void 0 : rawSwapData.fromNetwork,
2931
+ toCurrency: rawSwapData == null ? void 0 : rawSwapData.toCurrency,
2932
+ toNetwork: rawSwapData == null ? void 0 : rawSwapData.toNetwork,
2933
+ address: toAddress,
2934
+ amount: amount,
2935
+ fixed: false,
2936
+ extraId: toCurrencyExtraId != null ? toCurrencyExtraId : "",
2937
+ rateId: rawSwapData == null ? void 0 : rawSwapData.id,
2938
+ userIp: clientIpAddress,
2939
+ refund: refundAddress
2940
+ };
2941
+ Logger.log(`Sending create request: ${safeStringify(requestData)}`, loggerSource);
2942
+ const response = await axios.post(`${this._URL}/api/v2/exchange`, requestData);
2943
+ const result = response.data;
2944
+ Logger.log(`Creation result ${safeStringify(result)}`, loggerSource);
2945
+ if (result != null && result.id) {
2946
+ var _result$from, _result$from2, _result$to, _result$to2, _result$from4, _result$from5, _result$to4, _result$to5;
2947
+ if (typeof (result == null || (_result$from = result.from) == null ? void 0 : _result$from.amount) !== "number" || typeof (result == null || (_result$from2 = result.from) == null ? void 0 : _result$from2.address) !== "string" || typeof (result == null || (_result$to = result.to) == null ? void 0 : _result$to.amount) !== "number" || typeof (result == null || (_result$to2 = result.to) == null ? void 0 : _result$to2.address) !== "string") throw new Error(`Wrong swap creation result ${result}`);
2948
+ /* We use the returned rate preferably but if the retrieved
2949
+ * rate 0/null/undefined we calculate it manually */
2950
+ let rate = result.rate;
2951
+ if (typeof rate !== "number" || BigNumber(rate).isZero()) {
2952
+ var _result$to3, _result$from3;
2953
+ rate = BigNumber(result == null || (_result$to3 = result.to) == null ? void 0 : _result$to3.amount).div(result == null || (_result$from3 = result.from) == null ? void 0 : _result$from3.amount);
2954
+ } else {
2955
+ rate = BigNumber(rate);
2956
+ }
2957
+ return {
2958
+ result: true,
2959
+ swapId: result == null ? void 0 : result.id,
2960
+ fromCoin: fromCoin,
2961
+ fromAmount: AmountUtils.trim(result == null || (_result$from4 = result.from) == null ? void 0 : _result$from4.amount, fromCoin.digits),
2962
+ fromAddress: result == null || (_result$from5 = result.from) == null ? void 0 : _result$from5.address,
2963
+ toCoin: toCoin,
2964
+ toAmount: AmountUtils.trim(result == null || (_result$to4 = result.to) == null ? void 0 : _result$to4.amount, toCoin.digits),
2965
+ toAddress: result == null || (_result$to5 = result.to) == null ? void 0 : _result$to5.address,
2966
+ rate: AmountUtils.trim(rate, this._maxRateDigits)
2967
+ };
2968
+ }
2969
+ const errorMessage = `Swap creation succeeded but the response is wrong: ${safeStringify(response)}`;
2970
+ Logger.log(errorMessage, loggerSource);
2971
+ throw new Error(errorMessage);
2972
+ } catch (e) {
2973
+ var _e$response4, _e$response5;
2974
+ Logger.log(`Failed to create swap. Error is: ${safeStringify(e)}`, loggerSource);
2975
+ const composeFailResult = reason => ({
2976
+ result: false,
2977
+ reason: reason,
2978
+ partner: partner
2979
+ });
2980
+ const status = e == null || (_e$response4 = e.response) == null ? void 0 : _e$response4.status;
2981
+ const data = e == null || (_e$response5 = e.response) == null ? void 0 : _e$response5.data;
2982
+ if (status === 429) {
2983
+ Logger.log(`Returning fail - RPS limit exceeded ${data}`, loggerSource);
2984
+ return composeFailResult(SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED);
2985
+ }
2986
+ const texts422 = ["Pair cannot be processed by", "Currency not found", "Amount maximum is", "Amount minimum is"];
2987
+ const text403 = "IP address is forbidden";
2988
+ if (typeof data === "string" && (status === 403 && data.includes(text403) || status === 422 && texts422.find(text => data.includes(text)))) {
2989
+ Logger.log(`Returning retriable fail: ${status} - ${data}, ${partner}`, loggerSource);
2990
+ return composeFailResult(SwapProvider.CREATION_FAIL_REASONS.RETRIABLE_FAIL);
2991
+ }
2992
+ Logger.log(`Internal swapspace/rabbit error for ${partner}: ${safeStringify(e)}`, loggerSource);
2993
+ improveAndRethrow(e, loggerSource);
2994
+ }
2995
+ }
2996
+ _mapSwapspaceStatusToRabbitStatus(status) {
2997
+ switch (status) {
2998
+ case "waiting":
2999
+ return SwapProvider.SWAP_STATUSES.WAITING_FOR_PAYMENT;
3000
+ case "confirming":
3001
+ return SwapProvider.SWAP_STATUSES.CONFIRMING;
3002
+ case "exchanging":
3003
+ return SwapProvider.SWAP_STATUSES.EXCHANGING;
3004
+ case "sending":
3005
+ return SwapProvider.SWAP_STATUSES.PAYMENT_RECEIVED;
3006
+ case "finished":
3007
+ return SwapProvider.SWAP_STATUSES.COMPLETED;
3008
+ case "verifying":
3009
+ return SwapProvider.SWAP_STATUSES.EXCHANGING;
3010
+ case "refunded":
3011
+ return SwapProvider.SWAP_STATUSES.REFUNDED;
3012
+ case "expired":
3013
+ return SwapProvider.SWAP_STATUSES.EXPIRED;
3014
+ case "failed":
3015
+ return SwapProvider.SWAP_STATUSES.FAILED;
3016
+ default:
3017
+ throw new Error(`Unknown swapspace status: ${status}`);
3018
+ }
3019
+ }
3020
+ async getExistingSwapsDetailsAndStatus(swapIds) {
3021
+ var _this = this;
3022
+ const loggerSource = "getExistingSwapsDetailsAndStatus";
3023
+ try {
3024
+ if (swapIds.find(id => typeof id !== "string")) {
3025
+ throw new Error("Swap id is not string: " + safeStringify(swapIds));
3026
+ }
3027
+ const getNotFailingOn404 = async function getNotFailingOn404(swapId) {
3028
+ try {
3029
+ return await axios.get(`${_this._URL}/api/v2/exchange/${swapId}`);
3030
+ } catch (error) {
3031
+ var _error$response;
3032
+ if ((error == null || (_error$response = error.response) == null ? void 0 : _error$response.status) === 404) return [];
3033
+ throw error;
3034
+ }
3035
+ };
3036
+ const responses = await Promise.all(swapIds.map(swapId => getNotFailingOn404(swapId)));
3037
+ const wo404 = responses.flat();
3038
+ const swaps = wo404.map(r => r.data).map((swap, index) => {
3039
+ var _this$_supportedCoins10, _this$_supportedCoins11;
3040
+ const fromCoin = (_this$_supportedCoins10 = this._supportedCoins.find(i => i.code === swap.from.code && i.network === swap.from.network)) == null ? void 0 : _this$_supportedCoins10.coin;
3041
+ const toCoin = (_this$_supportedCoins11 = this._supportedCoins.find(i => i.code === swap.to.code && i.network === swap.to.network)) == null ? void 0 : _this$_supportedCoins11.coin;
3042
+ if (!fromCoin || !toCoin) {
3043
+ return []; // We skip swaps with not supported coins for now
3044
+ }
3045
+ const status = this._mapSwapspaceStatusToRabbitStatus(swap.status);
3046
+ const toDigits = status === SwapProvider.SWAP_STATUSES.REFUNDED ? fromCoin.digits : toCoin.digits;
3047
+ const addressToSendCoinsToSwapspace = swap.from.address;
3048
+ const toUtcTimestamp = timeStr => Date.parse(timeStr.match(/.+[Zz]$/) ? timeStr : `${timeStr}Z`);
3049
+ return new ExistingSwap(swapIds[index], status, toUtcTimestamp(swap.timestamps.createdAt), toUtcTimestamp(swap.timestamps.expiresAt), swap.confirmations, AmountUtils.trim(swap.rate, this._maxRateDigits), swap.refundAddress, addressToSendCoinsToSwapspace, fromCoin, AmountUtils.trim(swap.from.amount, fromCoin.digits), swap.from.transactionHash, swap.blockExplorerTransactionUrl.from, toCoin, AmountUtils.trim(swap.to.amount, toDigits), swap.to.transactionHash, swap.blockExplorerTransactionUrl.to, swap.to.address, swap.partner);
3050
+ }).flat();
3051
+ Logger.log(`Swap details result ${safeStringify(swaps)}`, loggerSource);
3052
+ return {
3053
+ result: true,
3054
+ swaps: swaps
3055
+ };
3056
+ } catch (e) {
3057
+ var _e$response6, _e$response7;
3058
+ Logger.log(`Failed to get swap details. Error is: ${safeStringify(e)}`, loggerSource);
3059
+ const composeFailResult = reason => ({
3060
+ result: false,
3061
+ reason: reason
3062
+ });
3063
+ const status = e == null || (_e$response6 = e.response) == null ? void 0 : _e$response6.status;
3064
+ const data = e == null || (_e$response7 = e.response) == null ? void 0 : _e$response7.data;
3065
+ if (status === 429) {
3066
+ Logger.log(`Returning fail - RPS limit exceeded ${data}`, loggerSource);
3067
+ return composeFailResult(SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED);
3068
+ }
3069
+ improveAndRethrow(e, loggerSource);
3070
+ }
3071
+ }
3072
+ isAddressValidForAsset(asset, address) {
3073
+ try {
3074
+ const assetData = this._supportedCoins.find(i => i.coin === asset);
3075
+ if (assetData) {
3076
+ let corrected = assetData.validationRegexp.trim();
3077
+ corrected = corrected[0] === "/" ? corrected.slice(1) : corrected;
3078
+ corrected = corrected[corrected.length - 1] === "/" ? corrected.slice(0, corrected.length - 1) : corrected;
3079
+ return address.match(corrected) != null;
3080
+ }
3081
+ } catch (e) {
3082
+ Logger.logError(e, "isAddressValidForAsset");
3083
+ }
3084
+ return false;
3085
+ }
3086
+ }
3087
+
3088
+ export { AmountUtils, AssetIcon, Blockchain, Button, Cache, Coin, EmailsApi, ExistingSwap, ExistingSwapWithFiatData, FiatCurrenciesService, LoadingDots, Logger, LogsStorage, Protocol, PublicSwapCreationInfo, SupportChat, SwapProvider, SwapspaceSwapProvider, improveAndRethrow, safeStringify };
2529
3089
  //# sourceMappingURL=index.modern.js.map