@rango-dev/queue-manager-rango-preset 0.1.10-next.77

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 (57) hide show
  1. package/dist/actions/checkStatus.d.ts +12 -0
  2. package/dist/actions/checkStatus.d.ts.map +1 -0
  3. package/dist/actions/createTransaction.d.ts +11 -0
  4. package/dist/actions/createTransaction.d.ts.map +1 -0
  5. package/dist/actions/executeTransaction.d.ts +13 -0
  6. package/dist/actions/executeTransaction.d.ts.map +1 -0
  7. package/dist/actions/scheduleNextStep.d.ts +13 -0
  8. package/dist/actions/scheduleNextStep.d.ts.map +1 -0
  9. package/dist/actions/start.d.ts +4 -0
  10. package/dist/actions/start.d.ts.map +1 -0
  11. package/dist/constants.d.ts +9 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/helpers.d.ts +159 -0
  14. package/dist/helpers.d.ts.map +1 -0
  15. package/dist/hooks.d.ts +19 -0
  16. package/dist/hooks.d.ts.map +1 -0
  17. package/dist/index.d.ts +10 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +8 -0
  20. package/dist/migration.d.ts +15 -0
  21. package/dist/migration.d.ts.map +1 -0
  22. package/dist/queue-manager-rango-preset.cjs.development.js +2249 -0
  23. package/dist/queue-manager-rango-preset.cjs.development.js.map +1 -0
  24. package/dist/queue-manager-rango-preset.cjs.production.min.js +2 -0
  25. package/dist/queue-manager-rango-preset.cjs.production.min.js.map +1 -0
  26. package/dist/queue-manager-rango-preset.esm.js +2242 -0
  27. package/dist/queue-manager-rango-preset.esm.js.map +1 -0
  28. package/dist/queueDef.d.ts +10 -0
  29. package/dist/queueDef.d.ts.map +1 -0
  30. package/dist/shared-api.d.ts +10 -0
  31. package/dist/shared-api.d.ts.map +1 -0
  32. package/dist/shared-errors.d.ts +56 -0
  33. package/dist/shared-errors.d.ts.map +1 -0
  34. package/dist/shared-sentry.d.ts +4 -0
  35. package/dist/shared-sentry.d.ts.map +1 -0
  36. package/dist/shared.d.ts +149 -0
  37. package/dist/shared.d.ts.map +1 -0
  38. package/dist/types.d.ts +46 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/package.json +59 -0
  41. package/readme.md +9 -0
  42. package/src/actions/checkStatus.ts +213 -0
  43. package/src/actions/createTransaction.ts +101 -0
  44. package/src/actions/executeTransaction.ts +117 -0
  45. package/src/actions/scheduleNextStep.ts +60 -0
  46. package/src/actions/start.ts +10 -0
  47. package/src/constants.ts +23 -0
  48. package/src/helpers.ts +1252 -0
  49. package/src/hooks.ts +75 -0
  50. package/src/index.ts +39 -0
  51. package/src/migration.ts +112 -0
  52. package/src/queueDef.ts +39 -0
  53. package/src/shared-api.ts +175 -0
  54. package/src/shared-errors.ts +156 -0
  55. package/src/shared-sentry.ts +24 -0
  56. package/src/shared.ts +333 -0
  57. package/src/types.ts +76 -0
package/src/helpers.ts ADDED
@@ -0,0 +1,1252 @@
1
+ import { ExecuterActions, QueueType } from '@rango-dev/queue-manager-core';
2
+ import {
3
+ BlockReason,
4
+ SwapActionTypes,
5
+ SwapQueueContext,
6
+ SwapQueueDef,
7
+ SwapStorage,
8
+ } from './types';
9
+ import {
10
+ EvmBlockchainMeta,
11
+ getBlockChainNameFromId,
12
+ Meta,
13
+ Network,
14
+ Transaction,
15
+ TransactionType,
16
+ WalletState,
17
+ WalletType,
18
+ } from '@rango-dev/wallets-shared';
19
+ import { Providers, readAccountAddress } from '@rango-dev/wallets-core';
20
+
21
+ import {
22
+ TronTransaction,
23
+ StarknetTransaction,
24
+ CosmosTransaction,
25
+ EvmTransaction,
26
+ SolanaTransaction,
27
+ Transfer as TransferTransaction,
28
+ } from 'rango-sdk';
29
+
30
+ import {
31
+ ERROR_MESSAGE_WAIT_FOR_CHANGE_NETWORK,
32
+ ERROR_MESSAGE_WAIT_FOR_WALLET,
33
+ ERROR_MESSAGE_WAIT_FOR_WALLET_DESCRIPTION,
34
+ } from './constants';
35
+ import { Manager } from '@rango-dev/queue-manager-core';
36
+ import { Status } from '@rango-dev/queue-manager-core';
37
+ import {
38
+ EventType,
39
+ getCurrentBlockchainOf,
40
+ getCurrentBlockchainOfOrNull,
41
+ getEvmApproveUrl,
42
+ getRelatedWalletOrNull,
43
+ MessageSeverity,
44
+ PendingSwap,
45
+ PendingSwapNetworkStatus,
46
+ PendingSwapStep,
47
+ prettifyErrorMessage,
48
+ StepStatus,
49
+ SwapStatus,
50
+ Wallet,
51
+ WalletTypeAndAddress,
52
+ } from './shared';
53
+ import { logRPCError } from './shared-sentry';
54
+ import { PrettyError } from './shared-errors';
55
+ import { mapAppErrorCodesToAPIErrorCode, reportFailed } from './shared-api';
56
+
57
+ type WhenTaskBlocked = Parameters<NonNullable<SwapQueueDef['whenTaskBlocked']>>;
58
+ type WhenTaskBlockedEvent = WhenTaskBlocked[0];
59
+ type WhenTaskBlockedMeta = WhenTaskBlocked[1];
60
+
61
+ let swapClaimedBy: { id: string } | null = null;
62
+
63
+ /**
64
+ *
65
+ * We simply use module-level variable to keep track of which queue has claimed the execution of parallel runnings.
66
+ *
67
+ */
68
+ function claimQueue() {
69
+ return {
70
+ claimedBy: () => swapClaimedBy?.id,
71
+ setClaimer: (queue_id: string) => {
72
+ swapClaimedBy = {
73
+ id: queue_id,
74
+ };
75
+ },
76
+ reset: () => {
77
+ swapClaimedBy = null;
78
+ },
79
+ };
80
+ }
81
+
82
+ /**
83
+ *
84
+ * Returns `steps`, if it's a `running` swap.
85
+ * Each `PendingSwap` has a `steps` inside it, `steps` shows how many tasks should be created and run to finish the swap.
86
+ *
87
+ */
88
+ export const getCurrentStep = (swap: PendingSwap): PendingSwapStep | null => {
89
+ return (
90
+ swap.steps.find(
91
+ (step) => step.status !== 'failed' && step.status !== 'success'
92
+ ) || null
93
+ );
94
+ };
95
+
96
+ /**
97
+ * When we are doing a swap, there are some common fields that will be updated together.
98
+ * This function helps us to update a swap status and also it will update some more fields like `extraMessageSeverity` based on the input.
99
+ */
100
+ export function updateSwapStatus({
101
+ getStorage,
102
+ setStorage,
103
+ nextStatus,
104
+ nextStepStatus,
105
+ message,
106
+ details,
107
+ errorCode = null,
108
+ }: {
109
+ getStorage: ExecuterActions<
110
+ SwapStorage,
111
+ SwapActionTypes,
112
+ SwapQueueContext
113
+ >['getStorage'];
114
+ setStorage: ExecuterActions<
115
+ SwapStorage,
116
+ SwapActionTypes,
117
+ SwapQueueContext
118
+ >['setStorage'];
119
+ nextStatus?: SwapStatus;
120
+ nextStepStatus?: StepStatus;
121
+ message?: string;
122
+ details?: string | null | undefined;
123
+ errorCode?: string | null;
124
+ }): {
125
+ swap: PendingSwap;
126
+ step: PendingSwapStep | null;
127
+ } {
128
+ const swap = getStorage().swapDetails;
129
+ const currentStep = getCurrentStep(swap);
130
+ if (!!nextStepStatus && !!currentStep) currentStep.status = nextStepStatus;
131
+
132
+ if (!!nextStatus) swap.status = nextStatus;
133
+
134
+ if (!!nextStatus && ['failed', 'success'].includes(nextStatus))
135
+ swap.finishTime = new Date().getTime().toString();
136
+
137
+ if (!!message) swap.extraMessage = message;
138
+
139
+ if (!!details) swap.extraMessageDetail = details;
140
+
141
+ if (!!nextStepStatus && ['failed'].includes(nextStepStatus)) {
142
+ //if user cancel the swap, we should pass relevant reason to the server.
143
+ const errorReason =
144
+ details && details.includes('Warning')
145
+ ? 'Swap canceled by user.'
146
+ : details;
147
+ swap.extraMessageSeverity = MessageSeverity.error;
148
+ reportFailed(
149
+ swap.requestId,
150
+ currentStep?.id || 1,
151
+ mapAppErrorCodesToAPIErrorCode(errorCode),
152
+ errorReason || '',
153
+ (currentStep
154
+ ? getRelatedWalletOrNull(swap, currentStep)?.walletType
155
+ : null) || null
156
+ ).then();
157
+ } else if (!!nextStepStatus && ['running'].includes(nextStepStatus))
158
+ swap.extraMessageSeverity = MessageSeverity.info;
159
+ else if (!!nextStepStatus && ['success', 'approved'].includes(nextStepStatus))
160
+ swap.extraMessageSeverity = MessageSeverity.success;
161
+ else if (nextStepStatus && ['waitingForApproval'].includes(nextStepStatus))
162
+ swap.extraMessageSeverity = MessageSeverity.warning;
163
+
164
+ if (nextStepStatus === 'running' && currentStep)
165
+ currentStep.startTransactionTime = new Date().getTime();
166
+
167
+ setStorage({
168
+ ...getStorage(),
169
+ swapDetails: swap,
170
+ });
171
+
172
+ return {
173
+ swap,
174
+ step: currentStep,
175
+ };
176
+ }
177
+
178
+ export function setStepTransactionIds(
179
+ { getStorage, setStorage }: ExecuterActions<SwapStorage, SwapActionTypes>,
180
+ txId: string | null,
181
+ eventType: EventType,
182
+ notifier: SwapQueueContext['notifier']
183
+ ): void {
184
+ const swap = getStorage().swapDetails;
185
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
186
+ const currentStep = getCurrentStep(swap)!;
187
+ currentStep.executedTransactionId = txId || currentStep.executedTransactionId;
188
+ setStorage({
189
+ ...getStorage(),
190
+ swapDetails: swap,
191
+ });
192
+ notifier({ eventType: eventType, swap: swap, step: currentStep });
193
+ }
194
+
195
+ /**
196
+ * If a swap needs a wallet to be connected,
197
+ * By calling this function some related fields will be updated to show a correct message and state for notfiying the user.
198
+ */
199
+ export function markRunningSwapAsWaitingForConnectingWallet(
200
+ {
201
+ getStorage,
202
+ setStorage,
203
+ }: Pick<ExecuterActions, 'getStorage' | 'setStorage'>,
204
+ reason: string,
205
+ reasonDetail: string
206
+ ): void {
207
+ const swap = getStorage().swapDetails as SwapStorage['swapDetails'];
208
+ const currentStep = getCurrentStep(swap);
209
+ if (!currentStep) return;
210
+ const currentTime = new Date();
211
+ swap.lastNotificationTime = currentTime.getTime().toString();
212
+
213
+ const isAlreadyMarked =
214
+ currentStep.networkStatus ===
215
+ PendingSwapNetworkStatus.WaitingForConnectingWallet &&
216
+ swap.networkStatusExtraMessage === reason &&
217
+ swap.networkStatusExtraMessageDetail === reasonDetail;
218
+
219
+ if (isAlreadyMarked) {
220
+ return;
221
+ }
222
+
223
+ currentStep.networkStatus =
224
+ PendingSwapNetworkStatus.WaitingForConnectingWallet;
225
+ swap.networkStatusExtraMessage = reason;
226
+ swap.networkStatusExtraMessageDetail = reasonDetail;
227
+
228
+ setStorage({
229
+ ...getStorage(),
230
+ swapDetails: swap,
231
+ });
232
+ }
233
+
234
+ /**
235
+ * If a swap needs a certain network to proceed,
236
+ * By calling this function some related fields will be updated to show a correct message and state for notfiying the user.
237
+ */
238
+ export function markRunningSwapAsSwitchingNetwork({
239
+ getStorage,
240
+ setStorage,
241
+ }: Pick<ExecuterActions, 'getStorage' | 'setStorage'>):
242
+ | {
243
+ swap: PendingSwap;
244
+ step: PendingSwapStep;
245
+ }
246
+ | undefined {
247
+ const swap = getStorage().swapDetails as SwapStorage['swapDetails'];
248
+
249
+ const currentStep = getCurrentStep(swap);
250
+ if (!currentStep) return;
251
+
252
+ // Generate message
253
+ const { type } = getRequiredWallet(swap);
254
+ const fromBlockchain = getCurrentBlockchainOf(swap, currentStep);
255
+ const reason = `Change ${type} wallet network to ${fromBlockchain}`;
256
+ let metamaskMessage = '';
257
+ if (type === WalletType.META_MASK)
258
+ metamaskMessage = `(Networks -> Select '${fromBlockchain}' network.)`;
259
+ const reasonDetail = `Please change your ${type} wallet network to ${fromBlockchain}. ${metamaskMessage}`;
260
+
261
+ const currentTime = new Date();
262
+ swap.lastNotificationTime = currentTime.getTime().toString();
263
+
264
+ currentStep.networkStatus = PendingSwapNetworkStatus.WaitingForNetworkChange;
265
+ swap.networkStatusExtraMessage = reason;
266
+ swap.networkStatusExtraMessageDetail = reasonDetail;
267
+
268
+ setStorage({
269
+ ...getStorage(),
270
+ swapDetails: swap,
271
+ });
272
+
273
+ return {
274
+ swap,
275
+ step: currentStep,
276
+ };
277
+ }
278
+
279
+ /**
280
+ * We are marking the queue as it depends on other queues to be run (on Parallel mode)
281
+ * By calling this function some related fields will be updated to show a correct message and state for notfiying the user.
282
+ */
283
+ export function markRunningSwapAsDependsOnOtherQueues({
284
+ getStorage,
285
+ setStorage,
286
+ }: Pick<ExecuterActions, 'getStorage' | 'setStorage'>):
287
+ | {
288
+ swap: PendingSwap;
289
+ step: PendingSwapStep;
290
+ }
291
+ | undefined {
292
+ const swap = getStorage().swapDetails as SwapStorage['swapDetails'];
293
+ const currentStep = getCurrentStep(swap);
294
+ if (!currentStep) return;
295
+
296
+ swap.networkStatusExtraMessage = '';
297
+ swap.networkStatusExtraMessageDetail = '';
298
+ currentStep.networkStatus = PendingSwapNetworkStatus.WaitingForQueue;
299
+
300
+ setStorage({
301
+ ...getStorage(),
302
+ swapDetails: swap,
303
+ });
304
+
305
+ return {
306
+ swap,
307
+ step: currentStep,
308
+ };
309
+ }
310
+
311
+ export function delay(ms: number): Promise<unknown> {
312
+ return new Promise((res) => setTimeout(res, ms));
313
+ }
314
+
315
+ export const isEvmTransaction = (tx: Transaction): tx is EvmTransaction =>
316
+ tx.type === TransactionType.EVM;
317
+
318
+ export const isCosmosTransaction = (tx: Transaction): tx is CosmosTransaction =>
319
+ tx.type === TransactionType.COSMOS;
320
+ export const isSolanaTransaction = (tx: Transaction): tx is SolanaTransaction =>
321
+ tx.type === TransactionType.SOLANA;
322
+ export const isTrasnferTransaction = (
323
+ tx: Transaction
324
+ ): tx is TransferTransaction => tx.type === TransactionType.TRANSFER;
325
+ export const isStarknetTransaction = (
326
+ tx: Transaction
327
+ ): tx is StarknetTransaction => tx.type === TransactionType.STARKNET;
328
+ export const isTronTransaction = (tx: Transaction): tx is TronTransaction =>
329
+ tx.type === TransactionType.TRON;
330
+
331
+ /**
332
+ *
333
+ * To execute a swap, we are keeping the user prefrences on what wallet they are going to use for a sepecific blockchain
334
+ * By passing the swap and the network we are looking for, it returns the wallet name that user selected.
335
+ *
336
+ */
337
+ export const getSwapWalletType = (
338
+ swap: PendingSwap,
339
+ network: Network
340
+ ): WalletType => {
341
+ return swap.wallets[network]?.walletType;
342
+ };
343
+
344
+ /**
345
+ *
346
+ * We are keeping the connected wallet in a specific structure (`Wallet`),
347
+ * By using this function we normally want to check a specific wallet is connected and exists or not.
348
+ *
349
+ */
350
+ export function isWalletNull(wallet: Wallet | null): boolean {
351
+ return (
352
+ wallet === null ||
353
+ wallet?.blockchains === null ||
354
+ wallet?.blockchains.length === 0
355
+ );
356
+ }
357
+
358
+ /**
359
+ * On our implementation for `wallets` package, We keep the instance in 2 ways
360
+ * If it's a single chain wallet, it returns the instance directly,
361
+ * If it's a multichain wallet, it returns a `Map` of instances.
362
+ * This function will get the `ETHEREUM` instance in both types.
363
+ */
364
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
365
+ export function getEvmProvider(providers: Providers, type: WalletType): any {
366
+ if (type && providers[type]) {
367
+ // we need this because provider can return an instance or a map of instances, so what you are doing here is try to detect that.
368
+ if (providers[type].size) return providers[type].get(Network.ETHEREUM);
369
+
370
+ return providers[type];
371
+ }
372
+ return null;
373
+ }
374
+
375
+ /**
376
+ * In a `PendingSwap`, each step needs a wallet to proceed,
377
+ * By using this function we can access what wallet exactly we need to run current step.
378
+ */
379
+ export function getRequiredWallet(swap: PendingSwap): {
380
+ type: WalletType | null;
381
+ network: Network | null;
382
+ address: string | null;
383
+ } {
384
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
385
+ const step = getCurrentStep(swap)!;
386
+ const bcName = getCurrentBlockchainOfOrNull(swap, step);
387
+ if (!bcName) {
388
+ return {
389
+ type: null,
390
+ network: null,
391
+ address: null,
392
+ };
393
+ }
394
+
395
+ const walletType = getSwapWalletType(swap, bcName);
396
+ const sourceWallet = swap.wallets[bcName];
397
+
398
+ return {
399
+ type: walletType || null,
400
+ network: bcName,
401
+ address: sourceWallet ? sourceWallet.address : null,
402
+ };
403
+ }
404
+
405
+ /**
406
+ * On EVM compatible wallets, There is one instance with different chains (like Polygon)
407
+ * To get the chain from instance we will use this function.
408
+ */
409
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
410
+ async function getChainId(provider: any): Promise<string | number | null> {
411
+ const chainId: number | string | null =
412
+ (await provider.request({ method: 'eth_chainId' })) || provider?.chainId;
413
+ return chainId;
414
+ }
415
+
416
+ /**
417
+ * For running a swap safely, we need to make sure about the state of wallet
418
+ * which means the netowrk/chain of wallet should be exactly on what a transaction needs.
419
+ */
420
+ export async function isNetworkMatchedForTransaction(
421
+ swap: PendingSwap,
422
+ step: PendingSwapStep,
423
+ wallet: Wallet | null,
424
+ meta: Meta,
425
+ providers: Providers
426
+ ): Promise<boolean> {
427
+ if (isWalletNull(wallet)) {
428
+ console.warn('wallet object is null');
429
+ return false;
430
+ }
431
+ const fromBlockChain = getCurrentBlockchainOfOrNull(swap, step);
432
+ if (!fromBlockChain) return false;
433
+
434
+ if (
435
+ !!meta.evmBasedChains.find(
436
+ (evmBlochain) => evmBlochain.name === fromBlockChain
437
+ )
438
+ ) {
439
+ try {
440
+ const sourceWallet = swap.wallets[fromBlockChain];
441
+ if (sourceWallet) {
442
+ if (
443
+ [
444
+ WalletType.META_MASK,
445
+ WalletType.BINANCE_CHAIN,
446
+ WalletType.XDEFI,
447
+ WalletType.WALLET_CONNECT,
448
+ WalletType.TRUST_WALLET,
449
+ WalletType.COIN98,
450
+ WalletType.EXODUS,
451
+ WalletType.OKX,
452
+ WalletType.COINBASE,
453
+ WalletType.TOKEN_POCKET,
454
+ WalletType.MATH,
455
+ WalletType.SAFEPAL,
456
+ WalletType.COSMOSTATION,
457
+ WalletType.CLOVER,
458
+ WalletType.BRAVE,
459
+ ].includes(sourceWallet.walletType)
460
+ ) {
461
+ const provider = getEvmProvider(providers, sourceWallet.walletType);
462
+ const chainId: number | string | null = await getChainId(provider);
463
+ if (chainId) {
464
+ const blockChain = getBlockChainNameFromId(
465
+ chainId,
466
+ Object.entries(meta.blockchains).map(
467
+ ([, blockchainMeta]) => blockchainMeta
468
+ )
469
+ );
470
+ if (
471
+ blockChain &&
472
+ blockChain.toLowerCase() === fromBlockChain.toLowerCase()
473
+ )
474
+ return true;
475
+ if (
476
+ blockChain &&
477
+ blockChain.toLowerCase() !== fromBlockChain.toLowerCase()
478
+ )
479
+ return false;
480
+ }
481
+ } else {
482
+ return true;
483
+ }
484
+ }
485
+ } catch (e) {
486
+ console.log(e);
487
+ }
488
+ return false;
489
+ }
490
+ return true;
491
+ }
492
+
493
+ /**
494
+ * Returns the wallet address, based on the current step of `PendingSwap`.
495
+ */
496
+ export const getCurrentAddressOf = (
497
+ swap: PendingSwap,
498
+ step: PendingSwapStep
499
+ ): string => {
500
+ const result =
501
+ swap.wallets[step.evmTransaction?.blockChain || ''] ||
502
+ swap.wallets[step.evmApprovalTransaction?.blockChain || ''] ||
503
+ swap.wallets[step.cosmosTransaction?.blockChain || ''] ||
504
+ swap.wallets[step.solanaTransaction?.blockChain || ''] ||
505
+ (step.transferTransaction?.fromWalletAddress
506
+ ? { address: step.transferTransaction?.fromWalletAddress }
507
+ : null) ||
508
+ null;
509
+ if (result == null) throw PrettyError.WalletMissing();
510
+ return result.address;
511
+ };
512
+
513
+ // Todo: Is it same with `getRequiredWallet`?
514
+ export function getRelatedWallet(
515
+ swap: PendingSwap,
516
+ currentStep: PendingSwapStep
517
+ ): WalletTypeAndAddress {
518
+ const walletAddress = getCurrentAddressOf(swap, currentStep);
519
+ const walletKV =
520
+ Object.keys(swap.wallets)
521
+ .map((k) => ({ k, v: swap.wallets[k] }))
522
+ .find(({ v }) => v.address === walletAddress) || null;
523
+ const blockchain = walletKV?.k || null;
524
+ const wallet = walletKV?.v || null;
525
+
526
+ const walletType = wallet?.walletType;
527
+ if (walletType === WalletType.UNKNOWN || wallet === null)
528
+ throw PrettyError.AssertionFailed(
529
+ `Wallet for source ${blockchain} not passed to transfer: walletType: ${walletType}`
530
+ );
531
+ return wallet;
532
+ }
533
+
534
+ export const isTxAlreadyCreated = (
535
+ swap: PendingSwap,
536
+ step: PendingSwapStep
537
+ ): boolean => {
538
+ const result =
539
+ swap.wallets[step.evmTransaction?.blockChain || ''] ||
540
+ swap.wallets[step.evmApprovalTransaction?.blockChain || ''] ||
541
+ swap.wallets[step.cosmosTransaction?.blockChain || ''] ||
542
+ swap.wallets[step.solanaTransaction?.blockChain || ''] ||
543
+ step.transferTransaction?.fromWalletAddress ||
544
+ null;
545
+
546
+ return result !== null;
547
+ };
548
+
549
+ export function resetNetworkStatus(
550
+ actions: ExecuterActions<SwapStorage, SwapActionTypes, SwapQueueContext>
551
+ ): void {
552
+ const { getStorage, setStorage } = actions;
553
+ const swap = getStorage().swapDetails;
554
+ const currentStep = getCurrentStep(swap);
555
+
556
+ if (currentStep?.networkStatus) {
557
+ currentStep.networkStatus = null;
558
+ setStorage({ ...getStorage(), swapDetails: swap });
559
+ }
560
+ }
561
+
562
+ export function updateNetworkStatus(
563
+ actions: ExecuterActions<SwapStorage, SwapActionTypes, SwapQueueContext>,
564
+ data: {
565
+ message: string;
566
+ details: string;
567
+ status: PendingSwapNetworkStatus | null;
568
+ } = {
569
+ message: '',
570
+ details: '',
571
+ status: null,
572
+ }
573
+ ): void {
574
+ const { message, details, status } = data;
575
+ const { getStorage, setStorage } = actions;
576
+ const swap = getStorage().swapDetails;
577
+ const currentStep = getCurrentStep(swap);
578
+
579
+ if (currentStep?.networkStatus) {
580
+ swap.networkStatusExtraMessage = message;
581
+ swap.networkStatusExtraMessageDetail = details;
582
+ currentStep.networkStatus = status;
583
+ setStorage({ ...getStorage(), swapDetails: swap });
584
+ }
585
+ }
586
+
587
+ /**
588
+ * Event handler for blocked tasks.
589
+ * If a transcation execution is manually blocked (like for parallel or waiting for walle),
590
+ * This function will be called by queue manager using `queue definition`.
591
+ *
592
+ * It checks if the required wallet is connected, unblock the queue to be run.
593
+ */
594
+ export function onBlockForConnectWallet(
595
+ event: WhenTaskBlockedEvent,
596
+ meta: WhenTaskBlockedMeta
597
+ ): void {
598
+ const { context, queue } = meta;
599
+ const swap = queue.getStorage().swapDetails as SwapStorage['swapDetails'];
600
+
601
+ if (!isRequiredWalletConnected(swap, context.state)) {
602
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
603
+ const currentStep = getCurrentStep(swap)!;
604
+ context.notifier({
605
+ eventType: 'waiting_for_connecting_wallet',
606
+ swap: swap,
607
+ step: currentStep,
608
+ });
609
+
610
+ markRunningSwapAsWaitingForConnectingWallet(
611
+ {
612
+ getStorage: queue.getStorage.bind(queue),
613
+ setStorage: queue.setStorage.bind(queue),
614
+ },
615
+ ERROR_MESSAGE_WAIT_FOR_WALLET,
616
+ event.reason.description
617
+ );
618
+
619
+ return;
620
+ }
621
+
622
+ queue.unblock();
623
+ }
624
+
625
+ /**
626
+ * Event handler for blocked tasks.
627
+ * If a transcation execution is manually blocked (like for parallel or waiting for walle),
628
+ * This function will be called by queue manager using `queue definition`.
629
+ *
630
+ * It checks if the required network is connected, unblock the queue to be run.
631
+ * Note: it automatically try to switch the network if its `provider` supports.
632
+ */
633
+ export function onBlockForChangeNetwork(
634
+ _event: WhenTaskBlockedEvent,
635
+ meta: WhenTaskBlockedMeta
636
+ ): void {
637
+ const { context, queue } = meta;
638
+ const swap = queue.getStorage().swapDetails as SwapStorage['swapDetails'];
639
+ const currentStep = getCurrentStep(swap);
640
+
641
+ if (!currentStep) return;
642
+
643
+ const result = markRunningSwapAsSwitchingNetwork({
644
+ getStorage: queue.getStorage.bind(queue),
645
+ setStorage: queue.setStorage.bind(queue),
646
+ });
647
+
648
+ if (result) {
649
+ context.notifier({
650
+ eventType: 'waiting_for_network_change',
651
+ swap: result.swap,
652
+ step: result.step,
653
+ });
654
+ }
655
+
656
+ // Try to auto switch
657
+ const { type, network } = getRequiredWallet(swap);
658
+ if (!!type && !!network) {
659
+ const result = context.switchNetwork(type, network);
660
+ if (result) {
661
+ result.then(() => {
662
+ queue.unblock();
663
+ });
664
+ }
665
+ }
666
+ }
667
+
668
+ /**
669
+ * Event handler for blocked tasks. (Parallel mode)
670
+ * If a transcation execution is manually blocked (like for parallel or waiting for walle),
671
+ * This function will be called by queue manager using `queue definition`.
672
+ *
673
+ * It checks the blocked tasks, if there is no active `claimed` queue, try to give it to the best candidate.
674
+ */
675
+ export function onDependsOnOtherQueues(
676
+ _event: WhenTaskBlockedEvent,
677
+ meta: WhenTaskBlockedMeta
678
+ ): void {
679
+ const { getBlockedTasks, forceExecute, queue, manager } = meta;
680
+ const { setClaimer, claimedBy, reset } = claimQueue();
681
+
682
+ // We only needs those blocked tasks that have DEPENDS_ON_OTHER_QUEUES reason.
683
+ const blockedTasks = getBlockedTasks().filter(
684
+ (task) => task.reason.reason === BlockReason.DEPENDS_ON_OTHER_QUEUES
685
+ );
686
+
687
+ if (blockedTasks.length === 0) {
688
+ return;
689
+ }
690
+
691
+ const claimerId = claimedBy();
692
+ const isClaimedByAnyQueue = !!claimerId;
693
+
694
+ // Check if any queue `claimed` before, if yes, we don't should do anything.
695
+ if (isClaimedByAnyQueue) {
696
+ // We need to keep the latest swap messages
697
+ markRunningSwapAsDependsOnOtherQueues({
698
+ getStorage: queue.getStorage.bind(queue),
699
+ setStorage: queue.setStorage.bind(queue),
700
+ });
701
+ return;
702
+ }
703
+
704
+ // Prioritize current queue to be run first.
705
+
706
+ let task = blockedTasks.find((task) => {
707
+ return task.queue_id === meta.queue_id;
708
+ });
709
+
710
+ // If current task isn't available anymore, fallback to first blocked task.
711
+ if (!task) {
712
+ const firstBlockedTask = blockedTasks[0];
713
+ task = firstBlockedTask;
714
+ }
715
+
716
+ setClaimer(task.queue_id);
717
+ const claimedStorage = task.storage.get() as SwapStorage;
718
+ const { type, network, address } = getRequiredWallet(
719
+ claimedStorage.swapDetails
720
+ );
721
+
722
+ // Run
723
+ forceExecute(task.queue_id, {
724
+ claimedBy: claimedBy(),
725
+ resetClaimedBy: () => {
726
+ reset();
727
+ // TODO: Use key generator
728
+ retryOn(`${type}-${network}-${address}`, manager);
729
+ },
730
+ });
731
+ }
732
+
733
+ export function isRequiredWalletConnected(
734
+ swap: PendingSwap,
735
+ getState: (type: WalletType) => WalletState
736
+ ): boolean {
737
+ const { type, address } = getRequiredWallet(swap);
738
+ if (!type || !address) {
739
+ return false;
740
+ }
741
+ const walletState = getState(type);
742
+ const { accounts } = walletState;
743
+ const connectedAccounts = accounts || [];
744
+
745
+ return connectedAccounts.some((account) => {
746
+ const { address: accountAddress } = readAccountAddress(account);
747
+ return address === accountAddress;
748
+ });
749
+ }
750
+
751
+ export function singTransaction(
752
+ actions: ExecuterActions<SwapStorage, SwapActionTypes, SwapQueueContext>
753
+ ): void {
754
+ const { getStorage, setStorage, failed, next, schedule, context } = actions;
755
+ const { meta, getSigners, notifier } = context;
756
+ const swap = getStorage().swapDetails;
757
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
758
+ const currentStep = getCurrentStep(swap)!;
759
+ const {
760
+ evmTransaction,
761
+ evmApprovalTransaction,
762
+ cosmosTransaction,
763
+ solanaTransaction,
764
+ transferTransaction,
765
+ } = currentStep;
766
+ const sourceWallet = getRelatedWallet(swap, currentStep);
767
+ const walletSigners = getSigners(sourceWallet.walletType);
768
+ const onFinish = () => {
769
+ if (actions.context.resetClaimedBy) {
770
+ actions.context.resetClaimedBy();
771
+ }
772
+ };
773
+
774
+ if (!!evmApprovalTransaction) {
775
+ const spenderContract = evmApprovalTransaction?.to;
776
+
777
+ if (!spenderContract)
778
+ throw PrettyError.AssertionFailed(
779
+ 'contract address is null for checking approval'
780
+ );
781
+
782
+ // Update swap status
783
+ const message = `waiting for approval of ${currentStep?.fromSymbol} coin ${
784
+ sourceWallet.walletType === WalletType.WALLET_CONNECT
785
+ ? 'on your mobile phone'
786
+ : ''
787
+ }`;
788
+ const updateResult = updateSwapStatus({
789
+ getStorage,
790
+ setStorage,
791
+ nextStepStatus: 'waitingForApproval',
792
+ message,
793
+ details:
794
+ 'Waiting for approve transaction to be mined and confirmed successfully',
795
+ });
796
+ notifier({
797
+ eventType: 'confirm_contract',
798
+ ...updateResult,
799
+ });
800
+
801
+ // Execute transaction
802
+ walletSigners.executeEvmTransaction(evmApprovalTransaction, meta).then(
803
+ (hash) => {
804
+ console.debug('transaction of approval minted successfully', hash);
805
+ const approveUrl = getEvmApproveUrl(
806
+ hash,
807
+ getCurrentBlockchainOf(swap, currentStep),
808
+ meta.evmBasedChains
809
+ );
810
+ currentStep.explorerUrl = [
811
+ ...(currentStep.explorerUrl || []),
812
+ {
813
+ url: approveUrl,
814
+ description: `approve`,
815
+ },
816
+ ];
817
+
818
+ // `currentStep` has been mutated, let's update storage.
819
+ setStorage({
820
+ ...getStorage(),
821
+ swapDetails: swap,
822
+ });
823
+ schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
824
+ next();
825
+ onFinish();
826
+ },
827
+
828
+ (error) => {
829
+ if (swap.status === 'failed') return;
830
+ console.debug('error in approving', error);
831
+ const { extraMessage, extraMessageDetail, extraMessageErrorCode } =
832
+ prettifyErrorMessage(error);
833
+ if (
834
+ error &&
835
+ error?.root &&
836
+ error?.root?.message &&
837
+ error?.root?.code &&
838
+ error?.root?.reason
839
+ ) {
840
+ logRPCError(error.root, swap, currentStep, sourceWallet?.walletType);
841
+ }
842
+
843
+ const updateResult = updateSwapStatus({
844
+ getStorage,
845
+ setStorage,
846
+ nextStatus: 'failed',
847
+ nextStepStatus: 'failed',
848
+ message: extraMessage,
849
+ details: extraMessageDetail,
850
+ errorCode: extraMessageErrorCode,
851
+ });
852
+ notifier({
853
+ eventType: 'contract_rejected',
854
+ ...updateResult,
855
+ });
856
+
857
+ failed();
858
+ onFinish();
859
+ }
860
+ );
861
+ return;
862
+ }
863
+
864
+ const executeMessage = 'executing transaction';
865
+ const executeDetails = `${
866
+ sourceWallet.walletType === WalletType.WALLET_CONNECT
867
+ ? 'Check your mobile phone'
868
+ : ''
869
+ }`;
870
+
871
+ if (!!transferTransaction) {
872
+ const updateResult = updateSwapStatus({
873
+ getStorage,
874
+ setStorage,
875
+ nextStepStatus: 'running',
876
+ message: executeMessage,
877
+ details: executeDetails,
878
+ });
879
+ notifier({
880
+ eventType: 'confirm_transfer',
881
+ ...updateResult,
882
+ });
883
+
884
+ walletSigners.executeTransfer(transferTransaction, meta).then(
885
+ (txId) => {
886
+ setStepTransactionIds(actions, txId, 'transfer_confirmed', notifier);
887
+ schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
888
+ next();
889
+ onFinish();
890
+ },
891
+ (error) => {
892
+ if (swap.status === 'failed') return;
893
+ const { extraMessage, extraMessageDetail, extraMessageErrorCode } =
894
+ prettifyErrorMessage(error);
895
+ const updateResult = updateSwapStatus({
896
+ getStorage,
897
+ setStorage,
898
+ nextStatus: 'failed',
899
+ nextStepStatus: 'failed',
900
+ message: extraMessage,
901
+ details: extraMessageDetail,
902
+ errorCode: extraMessageErrorCode,
903
+ });
904
+ notifier({
905
+ eventType: 'transfer_rejected',
906
+ ...updateResult,
907
+ });
908
+ failed();
909
+ onFinish();
910
+ }
911
+ );
912
+ } else if (!!evmTransaction) {
913
+ const updateResult = updateSwapStatus({
914
+ getStorage,
915
+ setStorage,
916
+ nextStepStatus: 'running',
917
+ message: executeMessage,
918
+ details: executeDetails,
919
+ });
920
+ notifier({
921
+ eventType: 'calling_smart_contract',
922
+ ...updateResult,
923
+ });
924
+
925
+ walletSigners.executeEvmTransaction(evmTransaction, meta).then(
926
+ (id) => {
927
+ setStepTransactionIds(actions, id, 'smart_contract_called', notifier);
928
+ schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
929
+ next();
930
+ onFinish();
931
+ },
932
+ (error) => {
933
+ if (swap.status === 'failed') return;
934
+ const { extraMessage, extraMessageDetail, extraMessageErrorCode } =
935
+ prettifyErrorMessage(error);
936
+ if (
937
+ error &&
938
+ error?.root &&
939
+ error?.root?.message &&
940
+ error?.root?.code &&
941
+ error?.root?.reason
942
+ ) {
943
+ logRPCError(error.root, swap, currentStep, sourceWallet?.walletType);
944
+ }
945
+ const updateResult = updateSwapStatus({
946
+ getStorage,
947
+ setStorage,
948
+ nextStatus: 'failed',
949
+ nextStepStatus: 'failed',
950
+ message: extraMessage,
951
+ details: extraMessageDetail,
952
+ errorCode: extraMessageErrorCode,
953
+ });
954
+ notifier({
955
+ eventType: 'smart_contract_call_failed',
956
+ ...updateResult,
957
+ });
958
+
959
+ failed();
960
+ onFinish();
961
+ }
962
+ );
963
+ } else if (!!cosmosTransaction) {
964
+ const updateResult = updateSwapStatus({
965
+ getStorage,
966
+ setStorage,
967
+ nextStepStatus: 'running',
968
+ message: executeMessage,
969
+ details: executeDetails,
970
+ });
971
+ notifier({
972
+ eventType: 'calling_smart_contract',
973
+ ...updateResult,
974
+ });
975
+
976
+ // If keplr wallet is executing contracts on terra, throw error. keplr doesn't support transfer or execute contracts. only IBC messages are supported
977
+ if (
978
+ (currentStep?.swapperId.toString() === 'TerraSwap' ||
979
+ (currentStep?.swapperId.toString() === 'ThorChain' &&
980
+ currentStep?.fromBlockchain === Network.TERRA) ||
981
+ (currentStep?.swapperId.toString() === 'Terra Bridge' &&
982
+ currentStep.fromBlockchain === Network.TERRA)) && // here we must allow ibc on terrastatus
983
+ sourceWallet.walletType === WalletType.KEPLR
984
+ ) {
985
+ const { extraMessage, extraMessageDetail, extraMessageErrorCode } =
986
+ prettifyErrorMessage(
987
+ 'Keplr only supports IBC Transactions on Terra. ' +
988
+ 'Using Terra Bridge, TerraSwap and THORChain is not possible with Keplr. Please use TerraStation or Leap wallet'
989
+ );
990
+ const updateResult = updateSwapStatus({
991
+ getStorage,
992
+ setStorage,
993
+ nextStatus: 'failed',
994
+ nextStepStatus: 'failed',
995
+ message: extraMessage,
996
+ details: extraMessageDetail,
997
+ errorCode: extraMessageErrorCode,
998
+ });
999
+ notifier({
1000
+ eventType: 'smart_contract_call_failed',
1001
+ ...updateResult,
1002
+ });
1003
+ failed();
1004
+ onFinish();
1005
+ return;
1006
+ }
1007
+
1008
+ walletSigners.executeCosmosMessage(cosmosTransaction, meta).then(
1009
+ // todo
1010
+ (id: string | null) => {
1011
+ setStepTransactionIds(actions, id, 'smart_contract_called', notifier);
1012
+ schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
1013
+ next();
1014
+ onFinish();
1015
+ },
1016
+ (error: string | null) => {
1017
+ if (swap.status === 'failed') return;
1018
+ const { extraMessage, extraMessageDetail, extraMessageErrorCode } =
1019
+ prettifyErrorMessage(error);
1020
+ const updateResult = updateSwapStatus({
1021
+ getStorage,
1022
+ setStorage,
1023
+ nextStatus: 'failed',
1024
+ nextStepStatus: 'failed',
1025
+ message: extraMessage,
1026
+ details: extraMessageDetail,
1027
+ errorCode: extraMessageErrorCode,
1028
+ });
1029
+ notifier({
1030
+ eventType: 'smart_contract_call_failed',
1031
+ ...updateResult,
1032
+ });
1033
+ failed();
1034
+ onFinish();
1035
+ }
1036
+ );
1037
+ } else if (!!solanaTransaction) {
1038
+ const updateResult = updateSwapStatus({
1039
+ getStorage,
1040
+ setStorage,
1041
+ nextStepStatus: 'running',
1042
+ message: executeMessage,
1043
+ details: executeDetails,
1044
+ });
1045
+ notifier({
1046
+ eventType: 'calling_smart_contract',
1047
+ ...updateResult,
1048
+ });
1049
+
1050
+ const tx = solanaTransaction;
1051
+ walletSigners.executeSolanaTransaction(tx, swap.requestId).then(
1052
+ (txId) => {
1053
+ setStepTransactionIds(actions, txId, 'smart_contract_called', notifier);
1054
+ schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
1055
+ next();
1056
+ onFinish();
1057
+ },
1058
+ (error) => {
1059
+ if (swap.status === 'failed') return;
1060
+ const { extraMessage, extraMessageDetail, extraMessageErrorCode } =
1061
+ prettifyErrorMessage(error);
1062
+ const updateResult = updateSwapStatus({
1063
+ getStorage,
1064
+ setStorage,
1065
+ nextStatus: 'failed',
1066
+ nextStepStatus: 'failed',
1067
+ message: extraMessage,
1068
+ details: extraMessageDetail,
1069
+ errorCode: extraMessageErrorCode,
1070
+ });
1071
+ notifier({
1072
+ eventType: 'smart_contract_call_failed',
1073
+ ...updateResult,
1074
+ });
1075
+ failed();
1076
+ onFinish();
1077
+ }
1078
+ );
1079
+ }
1080
+ }
1081
+
1082
+ export function checkWaitingForConnectWalletChange(params: {
1083
+ wallet_network: string;
1084
+ manager?: Manager;
1085
+ evmChains: EvmBlockchainMeta[];
1086
+ }): void {
1087
+ const { wallet_network, evmChains, manager } = params;
1088
+ const [wallet, network] = wallet_network.split('-');
1089
+
1090
+ // We only need change network for EVM chains.
1091
+ if (!evmChains.some((chain) => chain.name == network)) return;
1092
+
1093
+ manager?.getAll().forEach((q) => {
1094
+ const queueStorage = q.list.getStorage() as SwapStorage | undefined;
1095
+ const swap = queueStorage?.swapDetails;
1096
+ if (swap) {
1097
+ const currentStep = getCurrentStep(swap);
1098
+ if (currentStep) {
1099
+ const currentStepRequiredWallet =
1100
+ queueStorage?.swapDetails.wallets[currentStep.fromBlockchain]
1101
+ ?.walletType;
1102
+ const hasWaitingForConnect = Object.keys(q.list.state.tasks).some(
1103
+ (taskId) => {
1104
+ const task = q.list.state.tasks[taskId];
1105
+ return (
1106
+ task.status === Status.BLOCKED &&
1107
+ [BlockReason.WAIT_FOR_CONNECT_WALLET].includes(
1108
+ task.blockedFor?.reason
1109
+ )
1110
+ );
1111
+ }
1112
+ );
1113
+
1114
+ if (currentStepRequiredWallet === wallet && hasWaitingForConnect) {
1115
+ const queueInstance = q.list;
1116
+ const swap = queueInstance.getStorage()
1117
+ ?.swapDetails as SwapStorage['swapDetails'];
1118
+ const { type } = getRequiredWallet(swap);
1119
+ const description = ERROR_MESSAGE_WAIT_FOR_CHANGE_NETWORK(type);
1120
+
1121
+ q.list.block({
1122
+ reason: {
1123
+ reason: BlockReason.WAIT_FOR_NETWORK_CHANGE,
1124
+ description,
1125
+ },
1126
+ silent: true,
1127
+ });
1128
+
1129
+ markRunningSwapAsSwitchingNetwork({
1130
+ getStorage: queueInstance.getStorage.bind(queueInstance),
1131
+ setStorage: queueInstance.setStorage.bind(queueInstance),
1132
+ });
1133
+ }
1134
+ }
1135
+ }
1136
+ });
1137
+ }
1138
+
1139
+ export function checkWaitingForNetworkChange(manager?: Manager): void {
1140
+ manager?.getAll().forEach((q) => {
1141
+ const hasWaitingForNetwork = Object.keys(q.list.state.tasks).some(
1142
+ (taskId) => {
1143
+ const task = q.list.state.tasks[taskId];
1144
+ return (
1145
+ task.status === Status.BLOCKED &&
1146
+ [
1147
+ BlockReason.WAIT_FOR_NETWORK_CHANGE,
1148
+ BlockReason.DEPENDS_ON_OTHER_QUEUES,
1149
+ ].includes(task.blockedFor?.reason)
1150
+ );
1151
+ }
1152
+ );
1153
+
1154
+ if (hasWaitingForNetwork) {
1155
+ const swap = q.list.getStorage()
1156
+ ?.swapDetails as SwapStorage['swapDetails'];
1157
+ const { type } = getRequiredWallet(swap);
1158
+ const description = ERROR_MESSAGE_WAIT_FOR_WALLET_DESCRIPTION(type);
1159
+
1160
+ // Change the block reason to waiting for connecting wallet
1161
+ q.list.block({
1162
+ reason: {
1163
+ reason: BlockReason.WAIT_FOR_CONNECT_WALLET,
1164
+ description,
1165
+ },
1166
+ });
1167
+ }
1168
+ });
1169
+ }
1170
+
1171
+ /**
1172
+ *
1173
+ * Try to run blocked tasks by wallet and network name.
1174
+ * Goes through queues and extract blocked queues with matched wallet.
1175
+ * If found any blocked tasks with same wallet and network, runs them.
1176
+ * If not, runs only blocked tasks with matched wallet.
1177
+ *
1178
+ * @param wallet_network a string includes `wallet` type and `network` type.
1179
+ * @param manager
1180
+ * @returns
1181
+ */
1182
+ export function retryOn(
1183
+ wallet_network: string,
1184
+ manager?: Manager,
1185
+ options = { fallbackToOnlyWallet: true }
1186
+ ): void {
1187
+ const [wallet, network] = wallet_network.split('-');
1188
+ if (!wallet || !network) {
1189
+ return;
1190
+ }
1191
+
1192
+ const walletAndNetworkMatched: QueueType[] = [];
1193
+ const onlyWalletMatched: QueueType[] = [];
1194
+
1195
+ manager?.getAll().forEach((q) => {
1196
+ // retry only on affected queues
1197
+ if (q.status === Status.BLOCKED) {
1198
+ const queueStorage = q.list.getStorage() as SwapStorage | undefined;
1199
+ const swap = queueStorage?.swapDetails;
1200
+
1201
+ if (swap) {
1202
+ const currentStep = getCurrentStep(swap);
1203
+ if (currentStep) {
1204
+ if (
1205
+ currentStep.fromBlockchain == network &&
1206
+ queueStorage?.swapDetails.wallets[network]?.walletType === wallet
1207
+ ) {
1208
+ walletAndNetworkMatched.push(q.list);
1209
+ } else if (
1210
+ queueStorage?.swapDetails.wallets[currentStep.fromBlockchain]
1211
+ ?.walletType === wallet
1212
+ ) {
1213
+ onlyWalletMatched.push(q.list);
1214
+ }
1215
+ }
1216
+ }
1217
+ }
1218
+ });
1219
+
1220
+ // const isWaitingForConnectWallet = (status: Status) =>
1221
+ let finalQueueToBeRun: QueueType | undefined = undefined;
1222
+ if (walletAndNetworkMatched.length > 0) {
1223
+ finalQueueToBeRun = walletAndNetworkMatched[0];
1224
+
1225
+ if (walletAndNetworkMatched.length > 1) {
1226
+ for (let i = 1; i < walletAndNetworkMatched.length; i++) {
1227
+ const currentQueue = walletAndNetworkMatched[i];
1228
+
1229
+ markRunningSwapAsDependsOnOtherQueues({
1230
+ getStorage: currentQueue.getStorage.bind(currentQueue),
1231
+ setStorage: currentQueue.setStorage.bind(currentQueue),
1232
+ });
1233
+ }
1234
+ }
1235
+ } else if (onlyWalletMatched.length > 0 && options.fallbackToOnlyWallet) {
1236
+ finalQueueToBeRun = onlyWalletMatched[0];
1237
+ }
1238
+
1239
+ finalQueueToBeRun?.checkBlock();
1240
+ }
1241
+
1242
+ /*
1243
+ For avoiding conflict by making too many requests to wallet, we need to make sure
1244
+ We only run one request at a time (In parallel mode).
1245
+ */
1246
+ export function isNeedBlockQueueForParallel(step: PendingSwapStep): boolean {
1247
+ return (
1248
+ !!step.evmTransaction ||
1249
+ !!step.evmApprovalTransaction ||
1250
+ !!step.cosmosTransaction
1251
+ );
1252
+ }