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