@ledgerhq/live-common 34.54.0-nightly.20251209023841 → 34.54.0-nightly.20251209140356

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 (103) hide show
  1. package/lib/__tests__/test-helpers/environment.js +2 -0
  2. package/lib/__tests__/test-helpers/environment.js.map +1 -1
  3. package/lib/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
  4. package/lib/bridge/generic-alpaca/getAccountShape.js +3 -2
  5. package/lib/bridge/generic-alpaca/getAccountShape.js.map +1 -1
  6. package/lib/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  7. package/lib/bridge/generic-alpaca/prepareTransaction.js +7 -0
  8. package/lib/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  9. package/lib/e2e/index.d.ts +6 -0
  10. package/lib/e2e/index.d.ts.map +1 -1
  11. package/lib/exchange/swap/getIncompatibleCurrencyKeys.d.ts.map +1 -1
  12. package/lib/exchange/swap/getIncompatibleCurrencyKeys.js +4 -0
  13. package/lib/exchange/swap/getIncompatibleCurrencyKeys.js.map +1 -1
  14. package/lib/exchange/swap/transactionStrategies.d.ts +2 -1
  15. package/lib/exchange/swap/transactionStrategies.d.ts.map +1 -1
  16. package/lib/exchange/swap/transactionStrategies.js +7 -6
  17. package/lib/exchange/swap/transactionStrategies.js.map +1 -1
  18. package/lib/featureFlags/defaultFeatures.d.ts +2 -0
  19. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  20. package/lib/featureFlags/defaultFeatures.js +2 -0
  21. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  22. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  23. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +6 -0
  24. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  25. package/lib/wallet-api/Exchange/SwapError.d.ts +93 -0
  26. package/lib/wallet-api/Exchange/SwapError.d.ts.map +1 -0
  27. package/lib/wallet-api/Exchange/SwapError.js +142 -0
  28. package/lib/wallet-api/Exchange/SwapError.js.map +1 -0
  29. package/lib/wallet-api/Exchange/handleSwapErrors.d.ts +40 -0
  30. package/lib/wallet-api/Exchange/handleSwapErrors.d.ts.map +1 -0
  31. package/lib/wallet-api/Exchange/handleSwapErrors.js +112 -0
  32. package/lib/wallet-api/Exchange/handleSwapErrors.js.map +1 -0
  33. package/lib/wallet-api/Exchange/index.d.ts +4 -0
  34. package/lib/wallet-api/Exchange/index.d.ts.map +1 -0
  35. package/lib/wallet-api/Exchange/index.js +27 -0
  36. package/lib/wallet-api/Exchange/index.js.map +1 -0
  37. package/lib/wallet-api/Exchange/parser.d.ts +46 -0
  38. package/lib/wallet-api/Exchange/parser.d.ts.map +1 -0
  39. package/lib/wallet-api/Exchange/parser.js +97 -0
  40. package/lib/wallet-api/Exchange/parser.js.map +1 -0
  41. package/lib/wallet-api/Exchange/server.d.ts.map +1 -1
  42. package/lib/wallet-api/Exchange/server.js +226 -179
  43. package/lib/wallet-api/Exchange/server.js.map +1 -1
  44. package/lib-es/__tests__/test-helpers/environment.js +2 -0
  45. package/lib-es/__tests__/test-helpers/environment.js.map +1 -1
  46. package/lib-es/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
  47. package/lib-es/bridge/generic-alpaca/getAccountShape.js +3 -2
  48. package/lib-es/bridge/generic-alpaca/getAccountShape.js.map +1 -1
  49. package/lib-es/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  50. package/lib-es/bridge/generic-alpaca/prepareTransaction.js +7 -0
  51. package/lib-es/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  52. package/lib-es/e2e/index.d.ts +6 -0
  53. package/lib-es/e2e/index.d.ts.map +1 -1
  54. package/lib-es/exchange/swap/getIncompatibleCurrencyKeys.d.ts.map +1 -1
  55. package/lib-es/exchange/swap/getIncompatibleCurrencyKeys.js +4 -0
  56. package/lib-es/exchange/swap/getIncompatibleCurrencyKeys.js.map +1 -1
  57. package/lib-es/exchange/swap/transactionStrategies.d.ts +2 -1
  58. package/lib-es/exchange/swap/transactionStrategies.d.ts.map +1 -1
  59. package/lib-es/exchange/swap/transactionStrategies.js +7 -6
  60. package/lib-es/exchange/swap/transactionStrategies.js.map +1 -1
  61. package/lib-es/featureFlags/defaultFeatures.d.ts +2 -0
  62. package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
  63. package/lib-es/featureFlags/defaultFeatures.js +2 -0
  64. package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
  65. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  66. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +6 -0
  67. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  68. package/lib-es/wallet-api/Exchange/SwapError.d.ts +93 -0
  69. package/lib-es/wallet-api/Exchange/SwapError.d.ts.map +1 -0
  70. package/lib-es/wallet-api/Exchange/SwapError.js +128 -0
  71. package/lib-es/wallet-api/Exchange/SwapError.js.map +1 -0
  72. package/lib-es/wallet-api/Exchange/handleSwapErrors.d.ts +40 -0
  73. package/lib-es/wallet-api/Exchange/handleSwapErrors.d.ts.map +1 -0
  74. package/lib-es/wallet-api/Exchange/handleSwapErrors.js +106 -0
  75. package/lib-es/wallet-api/Exchange/handleSwapErrors.js.map +1 -0
  76. package/lib-es/wallet-api/Exchange/index.d.ts +4 -0
  77. package/lib-es/wallet-api/Exchange/index.d.ts.map +1 -0
  78. package/lib-es/wallet-api/Exchange/index.js +7 -0
  79. package/lib-es/wallet-api/Exchange/index.js.map +1 -0
  80. package/lib-es/wallet-api/Exchange/parser.d.ts +46 -0
  81. package/lib-es/wallet-api/Exchange/parser.d.ts.map +1 -0
  82. package/lib-es/wallet-api/Exchange/parser.js +90 -0
  83. package/lib-es/wallet-api/Exchange/parser.js.map +1 -0
  84. package/lib-es/wallet-api/Exchange/server.d.ts.map +1 -1
  85. package/lib-es/wallet-api/Exchange/server.js +223 -179
  86. package/lib-es/wallet-api/Exchange/server.js.map +1 -1
  87. package/package.json +73 -73
  88. package/src/__tests__/test-helpers/environment.ts +2 -0
  89. package/src/bridge/generic-alpaca/getAccountShape.ts +4 -2
  90. package/src/bridge/generic-alpaca/prepareTransaction.ts +7 -0
  91. package/src/bridge/generic-alpaca/tests/prepareTransaction.test.ts +42 -0
  92. package/src/exchange/swap/getIncompatibleCurrencyKeys.ts +4 -0
  93. package/src/exchange/swap/transactionStrategies.ts +8 -7
  94. package/src/featureFlags/defaultFeatures.ts +2 -0
  95. package/src/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.ts +6 -0
  96. package/src/wallet-api/Exchange/SwapError.test.ts +126 -0
  97. package/src/wallet-api/Exchange/SwapError.ts +159 -0
  98. package/src/wallet-api/Exchange/handleSwapErrors.test.ts +46 -0
  99. package/src/wallet-api/Exchange/handleSwapErrors.ts +161 -0
  100. package/src/wallet-api/Exchange/index.ts +26 -0
  101. package/src/wallet-api/Exchange/parser.test.ts +86 -0
  102. package/src/wallet-api/Exchange/parser.ts +119 -0
  103. package/src/wallet-api/Exchange/server.ts +287 -238
@@ -55,6 +55,10 @@ import { DeviceModelId } from "@ledgerhq/types-devices";
55
55
  import { setBroadcastTransaction } from "../../exchange/swap/setBroadcastTransaction";
56
56
  import { Transaction as EvmTransaction } from "@ledgerhq/coin-evm/types/index";
57
57
  import { padHexString } from "@ledgerhq/hw-app-eth";
58
+ import { createStepError, StepError, toError } from "./parser";
59
+ import { handleErrors } from "./handleSwapErrors";
60
+ import get from "lodash/get";
61
+ import { SwapError } from "./SwapError";
58
62
 
59
63
  export { ExchangeType };
60
64
 
@@ -376,243 +380,288 @@ export const handlers = ({
376
380
  );
377
381
  }),
378
382
  "custom.exchange.swap": customWrapper<ExchangeSwapParams, SwapResult>(async params => {
379
- if (!params) {
380
- tracking.startExchangeNoParams(manifest);
381
- throw new ServerError(createUnknownError({ message: "params is undefined" }));
382
- }
383
+ try {
384
+ if (!params) {
385
+ tracking.startExchangeNoParams(manifest);
386
+ throw new ServerError(createUnknownError({ message: "params is undefined" }));
387
+ }
383
388
 
384
- const {
385
- provider,
386
- fromAmount,
387
- fromAmountAtomic,
388
- quoteId,
389
- toNewTokenId,
390
- customFeeConfig,
391
- swapAppVersion,
392
- sponsored,
393
- isEmbedded,
394
- } = params;
395
-
396
- const trackingParams = {
397
- provider: params.provider,
398
- exchangeType: params.exchangeType,
399
- isEmbeddedSwap: isEmbedded,
400
- };
401
-
402
- tracking.startExchangeRequested(trackingParams);
403
-
404
- const exchangeStartParams: ExchangeStartParamsUiRequest = (await extractSwapStartParam(
405
- params,
406
- accounts,
407
- )) as SwapStartParamsUiRequest;
408
-
409
- const {
410
- fromCurrency,
411
- fromAccount,
412
- fromParentAccount,
413
- toCurrency,
414
- toAccount,
415
- toParentAccount,
416
- } = exchangeStartParams.exchange;
417
-
418
- if (!fromAccount || !fromCurrency) {
419
- throw new ServerError(createAccountNotFound(params.fromAccountId));
420
- }
389
+ const {
390
+ provider,
391
+ fromAmount,
392
+ fromAmountAtomic,
393
+ quoteId,
394
+ toNewTokenId,
395
+ customFeeConfig,
396
+ swapAppVersion,
397
+ sponsored,
398
+ isEmbedded,
399
+ } = params;
421
400
 
422
- const fromAccountAddress = fromParentAccount
423
- ? fromParentAccount.freshAddress
424
- : (fromAccount as Account).freshAddress;
425
-
426
- const toAccountAddress = toParentAccount
427
- ? toParentAccount.freshAddress
428
- : (toAccount as Account).freshAddress;
429
-
430
- // Step 1: Open the drawer and open exchange app
431
- const startExchange = async () => {
432
- return new Promise<{ transactionId: string; device?: ExchangeStartResult["device"] }>(
433
- (resolve, reject) => {
434
- uiExchangeStart({
435
- exchangeParams: exchangeStartParams,
436
- onSuccess: (nonce, device) => {
437
- tracking.startExchangeSuccess(trackingParams);
438
- resolve({ transactionId: nonce, device });
439
- },
440
- onCancel: error => {
441
- tracking.startExchangeFail(trackingParams);
442
- reject(error);
443
- },
444
- });
445
- },
446
- );
447
- };
448
-
449
- const { transactionId, device: deviceInfo } = await startExchange();
450
-
451
- const {
452
- binaryPayload,
453
- signature,
454
- payinAddress,
455
- swapId,
456
- payinExtraId,
457
- extraTransactionParameters,
458
- } = await retrieveSwapPayload({
459
- provider,
460
- deviceTransactionId: transactionId,
461
- fromAccountAddress,
462
- toAccountAddress,
463
- fromAccountCurrency: fromCurrency!.id,
464
- toAccountCurrency: toCurrency!.id,
465
- amount: fromAmount,
466
- amountInAtomicUnit: fromAmountAtomic,
467
- quoteId,
468
- toNewTokenId,
469
- }).catch((error: Error) => {
470
- throw error;
471
- });
472
-
473
- // Complete Swap
474
- const trackingCompleteParams = {
475
- provider: params.provider,
476
- exchangeType: params.exchangeType,
477
- isEmbeddedSwap: isEmbedded,
478
- };
479
- tracking.completeExchangeRequested(trackingCompleteParams);
480
-
481
- const strategyData = {
482
- recipient: payinAddress,
483
- amount: fromAmountAtomic,
484
- currency: fromCurrency as CryptoOrTokenCurrency,
485
- customFeeConfig: customFeeConfig ?? {},
486
- payinExtraId,
487
- extraTransactionParameters,
488
- sponsored,
489
- };
490
-
491
- const transaction: Transaction = await getStrategy(strategyData, "swap").catch(
492
- async error => {
493
- throw error;
494
- },
495
- );
401
+ const trackingParams = {
402
+ provider: params.provider,
403
+ exchangeType: params.exchangeType,
404
+ isEmbeddedSwap: isEmbedded,
405
+ };
496
406
 
497
- const mainFromAccount = getMainAccount(fromAccount, fromParentAccount);
407
+ tracking.startExchangeRequested(trackingParams);
498
408
 
499
- if (transaction.family !== mainFromAccount.currency.family) {
500
- return Promise.reject(
501
- new Error(
502
- `Account and transaction must be from the same family. Account family: ${mainFromAccount.currency.family}, Transaction family: ${transaction.family}`,
503
- ),
504
- );
505
- }
409
+ const exchangeStartParams: ExchangeStartParamsUiRequest = (await extractSwapStartParam(
410
+ params,
411
+ accounts,
412
+ )) as SwapStartParamsUiRequest;
413
+
414
+ const {
415
+ fromCurrency,
416
+ fromAccount,
417
+ fromParentAccount,
418
+ toCurrency,
419
+ toAccount,
420
+ toParentAccount,
421
+ } = exchangeStartParams.exchange;
422
+
423
+ if (!fromAccount || !fromCurrency) {
424
+ throw new ServerError(createAccountNotFound(params.fromAccountId));
425
+ }
506
426
 
507
- const accountBridge = getAccountBridge(fromAccount, fromParentAccount);
508
-
509
- /**
510
- * 'subAccountId' is used for ETH and it's ERC-20 tokens.
511
- * This field is ignored for BTC
512
- */
513
- const subAccountId =
514
- fromParentAccount && fromParentAccount.id !== fromAccount.id ? fromAccount.id : undefined;
515
-
516
- const bridgeTx = accountBridge.createTransaction(fromAccount);
517
- /**
518
- * We append the `recipient` to the tx created from `createTransaction`
519
- * to avoid having userGasLimit reset to null for ETH txs
520
- * cf. libs/ledger-live-common/src/families/ethereum/updateTransaction.ts
521
- */
522
- const tx = accountBridge.updateTransaction(
523
- {
524
- ...bridgeTx,
525
- recipient: transaction.recipient,
526
- },
527
- {
528
- ...transaction,
529
- feesStrategy: params.feeStrategy.toLowerCase(),
530
- subAccountId,
531
- },
532
- );
427
+ const fromAccountAddress = fromParentAccount
428
+ ? fromParentAccount.freshAddress
429
+ : (fromAccount as Account).freshAddress;
430
+
431
+ const toAccountAddress = toParentAccount
432
+ ? toParentAccount.freshAddress
433
+ : (toAccount as Account).freshAddress;
434
+
435
+ // Step 1: Open the drawer and open exchange app
436
+ const startExchange = async () => {
437
+ return new Promise<{ transactionId: string; device?: ExchangeStartResult["device"] }>(
438
+ (resolve, reject) => {
439
+ uiExchangeStart({
440
+ exchangeParams: exchangeStartParams,
441
+ onSuccess: (nonce, device) => {
442
+ tracking.startExchangeSuccess(trackingParams);
443
+ resolve({ transactionId: nonce, device });
444
+ },
445
+ onCancel: error => {
446
+ tracking.startExchangeFail(trackingParams);
447
+ reject(error);
448
+ },
449
+ });
450
+ },
451
+ );
452
+ };
533
453
 
534
- // Get amountExpectedTo and magnitudeAwareRate from binary payload
535
- const decodePayload = await decodeSwapPayload(binaryPayload);
536
- const amountExpectedTo = new BigNumber(decodePayload.amountToWallet.toString());
537
- const magnitudeAwareRate = tx.amount && amountExpectedTo.dividedBy(tx.amount);
538
- const refundAddress = decodePayload.refundAddress;
539
- const payoutAddress = decodePayload.payoutAddress;
454
+ let transactionId: string;
455
+ let deviceInfo: ExchangeStartResult["device"];
456
+
457
+ try {
458
+ const result = await startExchange();
459
+ transactionId = result.transactionId;
460
+ deviceInfo = result.device;
461
+ } catch (error) {
462
+ const rawError = get(error, "response.data.error", error);
463
+ const wrappedError = createStepError({
464
+ error: toError(rawError),
465
+ step: StepError.NONCE,
466
+ });
467
+ throw wrappedError;
468
+ }
540
469
 
541
- // tx.amount should be BigNumber
542
- tx.amount = new BigNumber(tx.amount);
470
+ const {
471
+ binaryPayload,
472
+ signature,
473
+ payinAddress,
474
+ swapId,
475
+ payinExtraId,
476
+ extraTransactionParameters,
477
+ } = await retrieveSwapPayload({
478
+ provider,
479
+ deviceTransactionId: transactionId,
480
+ fromAccountAddress,
481
+ toAccountAddress,
482
+ fromAccountCurrency: fromCurrency!.id,
483
+ toAccountCurrency: toCurrency!.id,
484
+ amount: fromAmount,
485
+ amountInAtomicUnit: fromAmountAtomic,
486
+ quoteId,
487
+ toNewTokenId,
488
+ }).catch((error: Error) => {
489
+ const wrappedError = createStepError({
490
+ error: get(error, "response.data.error", error),
491
+ step: StepError.PAYLOAD,
492
+ });
493
+
494
+ throw wrappedError;
495
+ });
543
496
 
544
- return new Promise((resolve, reject) =>
545
- uiSwap({
546
- exchangeParams: {
547
- exchangeType: ExchangeType.SWAP,
548
- provider: params.provider,
549
- transaction: tx,
550
- signature: signature,
551
- binaryPayload: binaryPayload,
552
- exchange: {
553
- fromAccount,
554
- fromParentAccount,
555
- toAccount,
556
- toParentAccount,
557
- fromCurrency: fromCurrency!,
558
- toCurrency: toCurrency!,
559
- },
560
- feesStrategy: params.feeStrategy,
561
- swapId: swapId,
562
- amountExpectedTo: amountExpectedTo.toNumber(),
563
- magnitudeAwareRate,
564
- refundAddress,
565
- payoutAddress,
566
- sponsored,
567
- },
568
- onSuccess: ({ operationHash, swapId }: { operationHash: string; swapId: string }) => {
569
- tracking.completeExchangeSuccess({
570
- ...trackingParams,
571
- currency: transaction.family,
572
- });
497
+ // Complete Swap
498
+ const trackingCompleteParams = {
499
+ provider: params.provider,
500
+ exchangeType: params.exchangeType,
501
+ isEmbeddedSwap: isEmbedded,
502
+ };
503
+ tracking.completeExchangeRequested(trackingCompleteParams);
504
+
505
+ const strategyData = {
506
+ recipient: payinAddress,
507
+ amount: fromAmountAtomic,
508
+ currency: fromCurrency as CryptoOrTokenCurrency,
509
+ customFeeConfig: customFeeConfig ?? {},
510
+ payinExtraId,
511
+ extraTransactionParameters,
512
+ sponsored,
513
+ };
573
514
 
574
- setBroadcastTransaction({
575
- provider,
576
- result: { operation: operationHash, swapId },
577
- sourceCurrencyId: fromCurrency.id,
578
- targetCurrencyId: toCurrency?.id,
579
- hardwareWalletType: deviceInfo?.modelId as DeviceModelId,
580
- swapAppVersion,
581
- fromAccountAddress,
582
- toAccountAddress,
583
- fromAmount,
584
- });
515
+ const transaction: Transaction = await getStrategy(strategyData, "swap");
516
+
517
+ const mainFromAccount = getMainAccount(fromAccount, fromParentAccount);
518
+
519
+ if (transaction.family !== mainFromAccount.currency.family) {
520
+ return Promise.reject(
521
+ new Error(
522
+ `Account and transaction must be from the same family. Account family: ${mainFromAccount.currency.family}, Transaction family: ${transaction.family}`,
523
+ ),
524
+ );
525
+ }
526
+
527
+ const accountBridge = getAccountBridge(fromAccount, fromParentAccount);
528
+
529
+ /**
530
+ * 'subAccountId' is used for ETH and it's ERC-20 tokens.
531
+ * This field is ignored for BTC
532
+ */
533
+ const subAccountId =
534
+ fromParentAccount && fromParentAccount.id !== fromAccount.id ? fromAccount.id : undefined;
585
535
 
586
- resolve({ operationHash, swapId });
536
+ const bridgeTx = accountBridge.createTransaction(fromAccount);
537
+ /**
538
+ * We append the `recipient` to the tx created from `createTransaction`
539
+ * to avoid having userGasLimit reset to null for ETH txs
540
+ * cf. libs/ledger-live-common/src/families/ethereum/updateTransaction.ts
541
+ */
542
+ const tx = accountBridge.updateTransaction(
543
+ {
544
+ ...bridgeTx,
545
+ recipient: transaction.recipient,
587
546
  },
588
- onCancel: error => {
589
- postSwapCancelled({
590
- provider: provider,
547
+ {
548
+ ...transaction,
549
+ feesStrategy: params.feeStrategy.toLowerCase(),
550
+ subAccountId,
551
+ },
552
+ );
553
+
554
+ // Get amountExpectedTo and magnitudeAwareRate from binary payload
555
+ const decodePayload = await decodeSwapPayload(binaryPayload);
556
+ const amountExpectedTo = new BigNumber(decodePayload.amountToWallet.toString());
557
+ const magnitudeAwareRate = tx.amount && amountExpectedTo.dividedBy(tx.amount);
558
+ const refundAddress = decodePayload.refundAddress;
559
+ const payoutAddress = decodePayload.payoutAddress;
560
+
561
+ // tx.amount should be BigNumber
562
+ tx.amount = new BigNumber(tx.amount);
563
+
564
+ return new Promise((resolve, reject) =>
565
+ uiSwap({
566
+ exchangeParams: {
567
+ exchangeType: ExchangeType.SWAP,
568
+ provider: params.provider,
569
+ transaction: tx,
570
+ signature: signature,
571
+ binaryPayload: binaryPayload,
572
+ exchange: {
573
+ fromAccount,
574
+ fromParentAccount,
575
+ toAccount,
576
+ toParentAccount,
577
+ fromCurrency: fromCurrency!,
578
+ toCurrency: toCurrency!,
579
+ },
580
+ feesStrategy: params.feeStrategy,
591
581
  swapId: swapId,
592
- swapStep: getSwapStepFromError(error),
593
- statusCode: error.name,
594
- errorMessage: error.message,
595
- sourceCurrencyId: fromCurrency.id,
596
- targetCurrencyId: toCurrency?.id,
597
- hardwareWalletType: deviceInfo?.modelId as DeviceModelId,
598
- swapType: quoteId ? "fixed" : "float",
599
- swapAppVersion,
600
- fromAccountAddress,
601
- toAccountAddress,
582
+ amountExpectedTo: amountExpectedTo.toNumber(),
583
+ magnitudeAwareRate,
602
584
  refundAddress,
603
585
  payoutAddress,
604
- fromAmount,
605
- seedIdFrom: mainFromAccount.seedIdentifier,
606
- seedIdTo: toParentAccount?.seedIdentifier || (toAccount as Account)?.seedIdentifier,
607
- data: (transaction as EvmTransaction).data
608
- ? `0x${padHexString((transaction as EvmTransaction).data?.toString("hex") || "")}`
609
- : "0x",
586
+ sponsored,
587
+ },
588
+ onSuccess: ({ operationHash, swapId }: { operationHash: string; swapId: string }) => {
589
+ tracking.completeExchangeSuccess({
590
+ ...trackingParams,
591
+ currency: transaction.family,
592
+ });
593
+
594
+ setBroadcastTransaction({
595
+ provider,
596
+ result: { operation: operationHash, swapId },
597
+ sourceCurrencyId: fromCurrency.id,
598
+ targetCurrencyId: toCurrency?.id,
599
+ hardwareWalletType: deviceInfo?.modelId as DeviceModelId,
600
+ swapAppVersion,
601
+ fromAccountAddress,
602
+ toAccountAddress,
603
+ fromAmount,
604
+ });
605
+
606
+ resolve({ operationHash, swapId });
607
+ },
608
+ onCancel: error => {
609
+ postSwapCancelled({
610
+ provider: provider,
611
+ swapId: swapId,
612
+ swapStep: getSwapStepFromError(error),
613
+ statusCode: error.name,
614
+ errorMessage: error.message,
615
+ sourceCurrencyId: fromCurrency.id,
616
+ targetCurrencyId: toCurrency?.id,
617
+ hardwareWalletType: deviceInfo?.modelId as DeviceModelId,
618
+ swapType: quoteId ? "fixed" : "float",
619
+ swapAppVersion,
620
+ fromAccountAddress,
621
+ toAccountAddress,
622
+ refundAddress,
623
+ payoutAddress,
624
+ fromAmount,
625
+ seedIdFrom: mainFromAccount.seedIdentifier,
626
+ seedIdTo: toParentAccount?.seedIdentifier || (toAccount as Account)?.seedIdentifier,
627
+ data: (transaction as EvmTransaction).data
628
+ ? `0x${padHexString((transaction as EvmTransaction).data?.toString("hex") || "")}`
629
+ : "0x",
630
+ });
631
+
632
+ reject(createStepError({ error, step: StepError.SIGNATURE }));
633
+ },
634
+ }),
635
+ );
636
+ } catch (error) {
637
+ // Skip DrawerClosedError
638
+ // do not redirect to the error screen
639
+ if (isDrawerClosedError(error)) {
640
+ throw error;
641
+ }
642
+
643
+ // Global catch for any errors during the swap process
644
+ // moved out as sonarcloud suggested to avoid 4 level nested functions
645
+ const createErrorRejector = (error: SwapError, reject: (error: SwapError) => void) => {
646
+ return () => reject(error);
647
+ };
648
+
649
+ const displayError = (error: SwapError): Promise<void> =>
650
+ new Promise((resolve, reject) => {
651
+ const rejectWithError = createErrorRejector(error, reject);
652
+ uiError({
653
+ error,
654
+ onSuccess: rejectWithError,
655
+ onCancel: rejectWithError,
610
656
  });
657
+ });
611
658
 
612
- reject(error);
613
- },
614
- }),
615
- );
659
+ await handleErrors(error, {
660
+ onDisplayError: displayError,
661
+ });
662
+
663
+ throw error;
664
+ }
616
665
  }),
617
666
 
618
667
  "custom.isReady": customWrapper<void, void>(async () => {
@@ -834,21 +883,21 @@ async function getStrategy(
834
883
  }
835
884
  }
836
885
 
837
- try {
838
- return await strategy({
839
- family,
840
- amount: new BigNumber(amount),
841
- recipient,
842
- customFeeConfig: convertedCustomFeeConfig,
843
- payinExtraId,
844
- extraTransactionParameters,
845
- customErrorType,
846
- sponsored,
847
- });
848
- } catch (error) {
849
- const errorMessage = error instanceof Error ? error.message : String(error);
850
- throw new Error(
851
- `Failed to execute transaction strategy for family: ${family}. Reason: ${errorMessage}`,
852
- );
853
- }
886
+ return strategy({
887
+ family,
888
+ amount: new BigNumber(amount),
889
+ recipient,
890
+ customFeeConfig: convertedCustomFeeConfig,
891
+ payinExtraId,
892
+ extraTransactionParameters,
893
+ customErrorType,
894
+ sponsored,
895
+ });
896
+ }
897
+
898
+ function isDrawerClosedError(error: unknown) {
899
+ if (!error || typeof error !== "object") return false;
900
+ return (
901
+ get(error, "name") === "DrawerClosedError" || get(error, "cause.name") === "DrawerClosedError"
902
+ );
854
903
  }