@metamask-previews/bridge-status-controller 71.2.1-preview-d3514bcb5 → 71.2.1-preview-ce4057bcb

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 (126) hide show
  1. package/CHANGELOG.md +22 -5
  2. package/dist/bridge-status-controller-method-action-types.cjs.map +1 -1
  3. package/dist/bridge-status-controller-method-action-types.d.cts +5 -1
  4. package/dist/bridge-status-controller-method-action-types.d.cts.map +1 -1
  5. package/dist/bridge-status-controller-method-action-types.d.mts +5 -1
  6. package/dist/bridge-status-controller-method-action-types.d.mts.map +1 -1
  7. package/dist/bridge-status-controller-method-action-types.mjs.map +1 -1
  8. package/dist/bridge-status-controller.cjs +161 -374
  9. package/dist/bridge-status-controller.cjs.map +1 -1
  10. package/dist/bridge-status-controller.d.cts +27 -7
  11. package/dist/bridge-status-controller.d.cts.map +1 -1
  12. package/dist/bridge-status-controller.d.mts +27 -7
  13. package/dist/bridge-status-controller.d.mts.map +1 -1
  14. package/dist/bridge-status-controller.mjs +162 -378
  15. package/dist/bridge-status-controller.mjs.map +1 -1
  16. package/dist/index.cjs +4 -1
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +1 -0
  19. package/dist/index.d.cts.map +1 -1
  20. package/dist/index.d.mts +1 -0
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +1 -0
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/strategy/batch-sell-strategy.cjs +101 -0
  25. package/dist/strategy/batch-sell-strategy.cjs.map +1 -0
  26. package/dist/strategy/batch-sell-strategy.d.cts +10 -0
  27. package/dist/strategy/batch-sell-strategy.d.cts.map +1 -0
  28. package/dist/strategy/batch-sell-strategy.d.mts +10 -0
  29. package/dist/strategy/batch-sell-strategy.d.mts.map +1 -0
  30. package/dist/strategy/batch-sell-strategy.mjs +97 -0
  31. package/dist/strategy/batch-sell-strategy.mjs.map +1 -0
  32. package/dist/strategy/batch-strategy.cjs +64 -0
  33. package/dist/strategy/batch-strategy.cjs.map +1 -0
  34. package/dist/strategy/batch-strategy.d.cts +10 -0
  35. package/dist/strategy/batch-strategy.d.cts.map +1 -0
  36. package/dist/strategy/batch-strategy.d.mts +10 -0
  37. package/dist/strategy/batch-strategy.d.mts.map +1 -0
  38. package/dist/strategy/batch-strategy.mjs +60 -0
  39. package/dist/strategy/batch-strategy.mjs.map +1 -0
  40. package/dist/strategy/evm-strategy.cjs +149 -0
  41. package/dist/strategy/evm-strategy.cjs.map +1 -0
  42. package/dist/strategy/evm-strategy.d.cts +38 -0
  43. package/dist/strategy/evm-strategy.d.cts.map +1 -0
  44. package/dist/strategy/evm-strategy.d.mts +38 -0
  45. package/dist/strategy/evm-strategy.d.mts.map +1 -0
  46. package/dist/strategy/evm-strategy.mjs +143 -0
  47. package/dist/strategy/evm-strategy.mjs.map +1 -0
  48. package/dist/strategy/index.cjs +70 -0
  49. package/dist/strategy/index.cjs.map +1 -0
  50. package/dist/strategy/index.d.cts +12 -0
  51. package/dist/strategy/index.d.cts.map +1 -0
  52. package/dist/strategy/index.d.mts +12 -0
  53. package/dist/strategy/index.d.mts.map +1 -0
  54. package/dist/strategy/index.mjs +68 -0
  55. package/dist/strategy/index.mjs.map +1 -0
  56. package/dist/strategy/intent-strategy.cjs +160 -0
  57. package/dist/strategy/intent-strategy.cjs.map +1 -0
  58. package/dist/strategy/intent-strategy.d.cts +17 -0
  59. package/dist/strategy/intent-strategy.d.cts.map +1 -0
  60. package/dist/strategy/intent-strategy.d.mts +17 -0
  61. package/dist/strategy/intent-strategy.d.mts.map +1 -0
  62. package/dist/strategy/intent-strategy.mjs +156 -0
  63. package/dist/strategy/intent-strategy.mjs.map +1 -0
  64. package/dist/strategy/non-evm-strategy.cjs +80 -0
  65. package/dist/strategy/non-evm-strategy.cjs.map +1 -0
  66. package/dist/strategy/non-evm-strategy.d.cts +15 -0
  67. package/dist/strategy/non-evm-strategy.d.cts.map +1 -0
  68. package/dist/strategy/non-evm-strategy.d.mts +15 -0
  69. package/dist/strategy/non-evm-strategy.d.mts.map +1 -0
  70. package/dist/strategy/non-evm-strategy.mjs +76 -0
  71. package/dist/strategy/non-evm-strategy.mjs.map +1 -0
  72. package/dist/strategy/types.cjs +13 -0
  73. package/dist/strategy/types.cjs.map +1 -0
  74. package/dist/strategy/types.d.cts +77 -0
  75. package/dist/strategy/types.d.cts.map +1 -0
  76. package/dist/strategy/types.d.mts +77 -0
  77. package/dist/strategy/types.d.mts.map +1 -0
  78. package/dist/strategy/types.mjs +10 -0
  79. package/dist/strategy/types.mjs.map +1 -0
  80. package/dist/types.cjs.map +1 -1
  81. package/dist/types.d.cts +16 -4
  82. package/dist/types.d.cts.map +1 -1
  83. package/dist/types.d.mts +16 -4
  84. package/dist/types.d.mts.map +1 -1
  85. package/dist/types.mjs.map +1 -1
  86. package/dist/utils/bridge.cjs +5 -1
  87. package/dist/utils/bridge.cjs.map +1 -1
  88. package/dist/utils/bridge.d.cts +2 -2
  89. package/dist/utils/bridge.d.cts.map +1 -1
  90. package/dist/utils/bridge.d.mts +2 -2
  91. package/dist/utils/bridge.d.mts.map +1 -1
  92. package/dist/utils/bridge.mjs +3 -0
  93. package/dist/utils/bridge.mjs.map +1 -1
  94. package/dist/utils/history.cjs +72 -20
  95. package/dist/utils/history.cjs.map +1 -1
  96. package/dist/utils/history.d.cts +19 -5
  97. package/dist/utils/history.d.cts.map +1 -1
  98. package/dist/utils/history.d.mts +19 -5
  99. package/dist/utils/history.d.mts.map +1 -1
  100. package/dist/utils/history.mjs +69 -19
  101. package/dist/utils/history.mjs.map +1 -1
  102. package/dist/utils/metrics.cjs +10 -7
  103. package/dist/utils/metrics.cjs.map +1 -1
  104. package/dist/utils/metrics.d.cts +7 -6
  105. package/dist/utils/metrics.d.cts.map +1 -1
  106. package/dist/utils/metrics.d.mts +7 -6
  107. package/dist/utils/metrics.d.mts.map +1 -1
  108. package/dist/utils/metrics.mjs +10 -7
  109. package/dist/utils/metrics.mjs.map +1 -1
  110. package/dist/utils/trace.cjs +4 -4
  111. package/dist/utils/trace.cjs.map +1 -1
  112. package/dist/utils/trace.d.cts +2 -2
  113. package/dist/utils/trace.d.cts.map +1 -1
  114. package/dist/utils/trace.d.mts +2 -2
  115. package/dist/utils/trace.d.mts.map +1 -1
  116. package/dist/utils/trace.mjs +4 -4
  117. package/dist/utils/trace.mjs.map +1 -1
  118. package/dist/utils/transaction.cjs +80 -54
  119. package/dist/utils/transaction.cjs.map +1 -1
  120. package/dist/utils/transaction.d.cts +25 -31
  121. package/dist/utils/transaction.d.cts.map +1 -1
  122. package/dist/utils/transaction.d.mts +25 -31
  123. package/dist/utils/transaction.d.mts.map +1 -1
  124. package/dist/utils/transaction.mjs +76 -52
  125. package/dist/utils/transaction.mjs.map +1 -1
  126. package/package.json +2 -2
@@ -9,26 +9,25 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_intentManager, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_addTransactionBatchFn, _BridgeStatusController_trace, _BridgeStatusController_onTransactionFailed, _BridgeStatusController_onTransactionConfirmed, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_addTxToHistory, _BridgeStatusController_rekeyHistoryItem, _BridgeStatusController_startPollingForTxId, _BridgeStatusController_handleFetchFailure, _BridgeStatusController_handleOldHistoryItem, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_setAndGetSrcTxHash, _BridgeStatusController_updateHistoryItem, _BridgeStatusController_deleteHistoryItem, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_handleApprovalTx, _BridgeStatusController_handleEvmTransactionBatch, _BridgeStatusController_trackPollingStatusUpdatedEvent, _BridgeStatusController_trackUnifiedSwapBridgeEvent;
13
- import { formatChainIdToHex, isNonEvmChainId, StatusTypes, getAccountHardwareType, UnifiedSwapBridgeEventName, isCrossChain, isTronChainId, isEvmTxData, MetricsActionType, MetaMetricsSwapsEventSource, isBitcoinTrade, isTronTrade, PollingStatus } from "@metamask/bridge-controller";
12
+ var _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_intentManager, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_addTransactionBatchFn, _BridgeStatusController_trace, _BridgeStatusController_onTransactionFailed, _BridgeStatusController_onTransactionConfirmed, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_addTxToHistory, _BridgeStatusController_rekeyHistoryItem, _BridgeStatusController_startPollingForTxId, _BridgeStatusController_handleFetchFailure, _BridgeStatusController_handleOldHistoryItem, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_setAndGetSrcTxHash, _BridgeStatusController_updateHistoryItem, _BridgeStatusController_deleteHistoryItem, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_executeSubmitStrategy, _BridgeStatusController_trackPollingStatusUpdatedEvent, _BridgeStatusController_trackUnifiedSwapBridgeEvent;
13
+ import { isNonEvmChainId, StatusTypes, getAccountHardwareType, UnifiedSwapBridgeEventName, isCrossChain, MetricsActionType, MetaMetricsSwapsEventSource, PollingStatus, formatChainIdToHex } from "@metamask/bridge-controller";
14
14
  import { StaticIntervalPollingController } from "@metamask/polling-controller";
15
15
  import { TransactionStatus, TransactionType, TransactionController } from "@metamask/transaction-controller";
16
16
  import { numberToHex } from "@metamask/utils";
17
17
  import { IntentManager } from "./bridge-status-controller.intent.mjs";
18
18
  import { BRIDGE_PROD_API_BASE_URL, BRIDGE_STATUS_CONTROLLER_NAME, DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE, MAX_ATTEMPTS, REFRESH_INTERVAL_MS } from "./constants.mjs";
19
+ import executeSubmitStrategy from "./strategy/index.mjs";
20
+ import { SubmitStep } from "./strategy/types.mjs";
19
21
  import { BridgeClientId } from "./types.mjs";
20
22
  import { getAccountByAddress } from "./utils/accounts.mjs";
21
23
  import { getJwt } from "./utils/authentication.mjs";
22
- import { stopPollingForQuotes, trackMetricsEvent } from "./utils/bridge.mjs";
24
+ import { getBatchSellTrades, stopPollingForQuotes, trackMetricsEvent } from "./utils/bridge.mjs";
23
25
  import { fetchBridgeTxStatus, getStatusRequestWithSrcTxHash, shouldSkipFetchDueToFetchFailures, shouldWaitForFinalBridgeStatus } from "./utils/bridge-status.mjs";
24
26
  import { getInitialHistoryItem, getMatchingHistoryEntryForTxMeta, rekeyHistoryItemInState, shouldPollHistoryItem, getMatchingHistoryEntryForApprovalTxMeta } from "./utils/history.mjs";
25
- import { getIntentFromQuote, mapIntentOrderStatusToTransactionStatus, postSubmitOrder } from "./utils/intent-api.mjs";
26
- import { signTypedMessage } from "./utils/keyring.mjs";
27
27
  import { getFinalizedTxProperties, getPriceImpactFromQuote, getRequestMetadataFromHistory, getRequestParamFromHistory, getTradeDataFromHistory, getEVMTxPropertiesFromTransactionMeta, getTxStatusesFromHistory, getPreConfirmationPropertiesFromQuote, getPollingStatusUpdatedProperties } from "./utils/metrics.mjs";
28
- import { getNetworkClientIdByChainId, getSelectedChainId } from "./utils/network.mjs";
29
- import { handleNonEvmTx } from "./utils/snaps.mjs";
30
- import { getApprovalTraceParams, getTraceParams } from "./utils/trace.mjs";
31
- import { handleApprovalDelay, handleMobileHardwareWalletDelay, generateActionId, waitForTxConfirmation, getTransactionMetaById, addTransactionBatch, addSyntheticTransaction, getTransactions, submitEvmTransaction, checkIsDelegatedAccount, isCrossChainTx, toQuoteAndTxMetadata, getAddTransactionBatchParams } from "./utils/transaction.mjs";
28
+ import { getSelectedChainId } from "./utils/network.mjs";
29
+ import { getTraceParams } from "./utils/trace.mjs";
30
+ import { getTransactionMetaById, getTransactions, checkIsDelegatedAccount, isCrossChainTx, updateTransactionsInBatch, hasNestedSwapTransactions } from "./utils/transaction.mjs";
32
31
  const metadata = {
33
32
  // We want to persist the bridge status state so that we can show the proper data for the Activity list
34
33
  // basically match the behavior of TransactionController
@@ -45,6 +44,7 @@ const MESSENGER_EXPOSED_METHODS = [
45
44
  'resetState',
46
45
  'submitTx',
47
46
  'submitIntent',
47
+ 'submitBatchSell',
48
48
  'restartPollingForFailedAttempts',
49
49
  'getBridgeHistoryItemByTxMetaId',
50
50
  ];
@@ -76,6 +76,7 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
76
76
  historyKey,
77
77
  status: StatusTypes.FAILED,
78
78
  txHash: isApprovalTxMeta ? undefined : txMeta.hash,
79
+ completionTime: Date.now(),
79
80
  });
80
81
  if (txMeta.status === TransactionStatus.rejected) {
81
82
  return;
@@ -98,11 +99,13 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
98
99
  historyKey,
99
100
  txHash: txMeta.hash,
100
101
  });
101
- switch (txMeta.type) {
102
- case TransactionType.swap:
102
+ const isSwap = txMeta.type === TransactionType.swap || hasNestedSwapTransactions(txMeta);
103
+ switch (isSwap) {
104
+ case true:
103
105
  __classPrivateFieldGet(this, _BridgeStatusController_updateHistoryItem, "f").call(this, {
104
106
  historyKey,
105
107
  status: StatusTypes.COMPLETE,
108
+ completionTime: Date.now(),
106
109
  });
107
110
  __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Completed, historyKey);
108
111
  break;
@@ -239,10 +242,9 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
239
242
  __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, historyKey);
240
243
  });
241
244
  });
242
- _BridgeStatusController_addTxToHistory.set(this, (...args) => {
243
- const { historyKey, txHistoryItem } = getInitialHistoryItem(...args);
245
+ _BridgeStatusController_addTxToHistory.set(this, (historyKey, ...args) => {
246
+ const txHistoryItem = getInitialHistoryItem(...args);
244
247
  this.update((state) => {
245
- // Use actionId as key for pre-submission, or txMeta.id for post-submission
246
248
  state.txHistory[historyKey] = txHistoryItem;
247
249
  });
248
250
  return historyKey;
@@ -251,14 +253,15 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
251
253
  * Rekeys a history item from actionId to txMeta.id after successful submission.
252
254
  * Also updates txMetaId and srcTxHash which weren't available pre-submission.
253
255
  *
254
- * @param actionId - The actionId used as the temporary key for the history item
256
+ * @param oldKey - The temporary key to use for the history item, usually the actionId
257
+ * @param newKey - The new key to use, typcally the txmeta.id
255
258
  * @param txMeta - The transaction meta from the successful submission
256
259
  * @param txMeta.id - The transaction meta id to use as the new key
257
260
  * @param txMeta.hash - The transaction hash to set on the history item
258
261
  */
259
- _BridgeStatusController_rekeyHistoryItem.set(this, (actionId, txMeta) => {
262
+ _BridgeStatusController_rekeyHistoryItem.set(this, (oldKey, newKey, txMeta) => {
260
263
  this.update((state) => {
261
- rekeyHistoryItemInState(state, actionId, txMeta);
264
+ rekeyHistoryItemInState(state, oldKey, newKey, txMeta);
262
265
  });
263
266
  });
264
267
  _BridgeStatusController_startPollingForTxId.set(this, (txId) => {
@@ -289,7 +292,7 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
289
292
  if (!bridgeTxMeta?.id) {
290
293
  throw new Error('Cannot start polling: bridgeTxMeta.id is required for polling');
291
294
  }
292
- const historyKey = __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, txHistoryMeta);
295
+ const historyKey = __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, bridgeTxMeta.id, txHistoryMeta);
293
296
  __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, historyKey);
294
297
  };
295
298
  // This will be called after you call this.startPolling()
@@ -484,7 +487,7 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
484
487
  });
485
488
  return localTxHash;
486
489
  });
487
- _BridgeStatusController_updateHistoryItem.set(this, ({ historyKey, status, txHash, attempts, }) => {
490
+ _BridgeStatusController_updateHistoryItem.set(this, ({ historyKey, status, txHash, attempts, completionTime, }) => {
488
491
  if (!historyKey) {
489
492
  return;
490
493
  }
@@ -498,6 +501,9 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
498
501
  if (attempts) {
499
502
  currentState.txHistory[historyKey].attempts = attempts;
500
503
  }
504
+ if (completionTime) {
505
+ currentState.txHistory[historyKey].completionTime = completionTime;
506
+ }
501
507
  });
502
508
  });
503
509
  _BridgeStatusController_deleteHistoryItem.set(this, (historyKey) => {
@@ -533,249 +539,134 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
533
539
  * TX SUBMISSION HANDLING
534
540
  *******************************************************
535
541
  */
536
- _BridgeStatusController_handleApprovalTx.set(this, async (quoteResponse, isBridgeTx, srcChainId, approval, resetApproval, requireApproval) => {
537
- if (approval && isEvmTxData(approval)) {
538
- const approveTx = async () => {
539
- if (resetApproval) {
540
- await submitEvmTransaction({
541
- messenger: this.messenger,
542
- transactionType: TransactionType.bridgeApproval,
543
- trade: resetApproval,
544
- });
542
+ _BridgeStatusController_executeSubmitStrategy.set(this, async (params, sharedHistoryItemProperties) => {
543
+ let tradeTxMeta;
544
+ const steps = executeSubmitStrategy(params);
545
+ // Each submission strategy determines when to execute step, which means these actions can happen in any order
546
+ for await (const { type, payload } of steps) {
547
+ try {
548
+ switch (type) {
549
+ case SubmitStep.RekeyHistoryItem:
550
+ __classPrivateFieldGet(this, _BridgeStatusController_rekeyHistoryItem, "f").call(this, payload.oldHistoryKey, payload.newHistoryKey, payload.tradeMeta);
551
+ break;
552
+ case SubmitStep.UpdateBatchTransactions:
553
+ updateTransactionsInBatch({
554
+ messenger: this.messenger,
555
+ allTradesWithMetadata: payload.quoteAndTxMetas,
556
+ });
557
+ break;
558
+ case SubmitStep.SetTradeMeta:
559
+ tradeTxMeta = payload.tradeMeta;
560
+ break;
561
+ case SubmitStep.AddHistoryItem:
562
+ __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, payload.historyKey, {
563
+ ...payload,
564
+ ...sharedHistoryItemProperties,
565
+ quoteResponse: payload.quoteResponse,
566
+ accountAddress: params.selectedAccount.address,
567
+ isStxEnabled: params.isStxEnabled,
568
+ slippagePercentage: 0, // TODO include slippage provided by quote if using dynamic slippage, or slippage from quote request
569
+ });
570
+ break;
571
+ case SubmitStep.StartPolling:
572
+ __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, payload.historyKey);
573
+ break;
574
+ case SubmitStep.PublishCompletedEvent:
575
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Completed, payload.historyKey);
576
+ break;
577
+ /* c8 ignore start */
578
+ default:
579
+ throw new Error(`Unknown submit step type: ${String(type)}`);
580
+ /* c8 ignore end */
545
581
  }
546
- const approvalTxMeta = await submitEvmTransaction({
547
- messenger: this.messenger,
548
- transactionType: isBridgeTx
549
- ? TransactionType.bridgeApproval
550
- : TransactionType.swapApproval,
551
- trade: approval,
552
- requireApproval,
553
- });
554
- await handleApprovalDelay(srcChainId);
555
- return approvalTxMeta;
556
- };
557
- return await __classPrivateFieldGet(this, _BridgeStatusController_trace, "f").call(this, getApprovalTraceParams(quoteResponse, false), approveTx);
558
- }
559
- return undefined;
560
- });
561
- /**
562
- * Submits batched EVM transactions to the TransactionController
563
- *
564
- * @param args - The parameters for the transaction
565
- * @param args.isBridgeTx - Whether the transaction is a bridge transaction
566
- * @param args.quoteResponse - The quote response containing the approval and trade data
567
- * @param args.requireApproval - Whether to require approval for the transaction
568
- * @param args.isDelegatedAccount - Whether the account is a delegated account
569
- * @returns The approvalMeta and tradeMeta for the batched transaction
570
- */
571
- _BridgeStatusController_handleEvmTransactionBatch.set(this, async ({ requireApproval, isDelegatedAccount, isBridgeTx, quoteResponse, }) => {
572
- const tradeData = toQuoteAndTxMetadata({
573
- quoteResponse,
574
- isBridgeTx,
575
- });
576
- const transactionParams = await getAddTransactionBatchParams({
577
- tradeData,
578
- requireApproval,
579
- isDelegatedAccount,
580
- messenger: this.messenger,
581
- atomic: true,
582
- disable7702:
583
- // Enable 7702 batching when the quote includes gasless 7702 support,
584
- quoteResponse.quote.gasIncluded7702
585
- ? false
586
- : // or when the account is already delegated (to avoid the in-flight transaction limit for delegated accounts)
587
- !isDelegatedAccount ||
588
- // For gasless transactions with STX/sendBundle we keep disabling 7702.
589
- quoteResponse.quote.gasIncluded,
590
- isGasFeeSponsored: Boolean(quoteResponse.quote.gasSponsored),
591
- isGasFeeIncluded: Boolean(quoteResponse.quote.gasIncluded7702),
592
- });
593
- const { tradeMeta, approvalMeta } = await addTransactionBatch(this.messenger, __classPrivateFieldGet(this, _BridgeStatusController_addTransactionBatchFn, "f"), tradeData, transactionParams);
594
- if (!tradeMeta) {
595
- throw new Error('Failed to update cross-chain swap transaction batch: tradeMeta not found');
582
+ }
583
+ catch (error) {
584
+ console.error('Failed to add to bridge history and start polling.', error);
585
+ }
596
586
  }
597
- return { tradeMeta, approvalMeta };
587
+ return tradeTxMeta;
598
588
  });
599
589
  /**
600
590
  * Submits a cross-chain swap transaction
601
591
  *
602
592
  * @param accountAddress - The address of the account to submit the transaction for
603
- * @param quoteResponse - The quote response
604
- * @param isStxEnabledOnClient - Whether smart transactions are enabled on the client, for example the getSmartTransactionsEnabled selector value from the extension
593
+ * @param maybeQuoteResponses - A single quote response or an array of quote responses
594
+ * @param isStxEnabled - Whether smart transactions are enabled on the client, for example the getSmartTransactionsEnabled selector value from the extension
605
595
  * @param quotesReceivedContext - The context for the QuotesReceived event
606
596
  * @param location - The entry point from which the user initiated the swap or bridge (e.g. Main View, Token View, Trending Explore)
607
597
  * @param abTests - Legacy A/B test context for `ab_tests` (backward compatibility)
608
598
  * @param activeAbTests - New A/B test context for `active_ab_tests` (migration target). Attributes events to specific experiments.
609
599
  * @param tokenSecurityTypeDestination - The security classification of the destination token, supplied by the client (e.g. from token security/scanning data). Pass `null` when no security data is available.
600
+ * @param batchSellTrades - Contains transaction data for the quotes, provided by the obtainGaslessBatch API
610
601
  * @returns The transaction meta
602
+ * @throws An error if transaction submission fails before it gets published
611
603
  */
612
- this.submitTx = async (accountAddress, quoteResponse, isStxEnabledOnClient, quotesReceivedContext, location = MetaMetricsSwapsEventSource.MainView, abTests, activeAbTests, tokenSecurityTypeDestination) => {
613
- stopPollingForQuotes(this.messenger, quoteResponse.featureId, quotesReceivedContext);
604
+ this.submitTx = async (accountAddress, maybeQuoteResponses, isStxEnabled, quotesReceivedContext, location = MetaMetricsSwapsEventSource.MainView, abTests, activeAbTests, tokenSecurityTypeDestination, batchSellTrades) => {
605
+ /**
606
+ * If there are multiple quote responses, we assume that they all originate from the same src chain
607
+ * and the same account. In this case its safe to use the first quote response's properties for
608
+ * metrics and other pre-submission logic
609
+ */
610
+ const quoteResponses = Array.isArray(maybeQuoteResponses)
611
+ ? maybeQuoteResponses
612
+ : [maybeQuoteResponses];
613
+ const quoteResponse = quoteResponses[0];
614
+ const { featureId, quote } = quoteResponse;
615
+ const startTime = Date.now();
616
+ stopPollingForQuotes(this.messenger, featureId, quotesReceivedContext);
614
617
  const selectedAccount = getAccountByAddress(this.messenger, accountAddress);
615
618
  if (!selectedAccount) {
616
619
  throw new Error('Failed to submit cross-chain swap transaction: undefined multichain account');
617
620
  }
618
621
  const accountHardwareType = getAccountHardwareType(selectedAccount);
619
- const preConfirmationProperties = getPreConfirmationPropertiesFromQuote(quoteResponse, isStxEnabledOnClient, accountHardwareType, location, abTests, activeAbTests, tokenSecurityTypeDestination);
620
- let txMeta;
621
- let approvalTxId;
622
- let isDelegatedAccount = false;
623
- const startTime = Date.now();
624
- const isBridgeTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
625
- const isTronTx = isTronChainId(quoteResponse.quote.srcChainId);
622
+ /**
623
+ * For hardware wallets on Mobile, this is fixes an issue where the Ledger does not get prompted for the 2nd approval.
624
+ * Extension does not have this issue
625
+ */
626
+ const requireApproval = __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f") === BridgeClientId.MOBILE && accountHardwareType !== null;
627
+ const isBridgeTx = isCrossChain(quote.srcChainId, quote.destChainId);
628
+ const preConfirmationProperties = getPreConfirmationPropertiesFromQuote(quoteResponse, isStxEnabled, accountHardwareType, location, abTests, activeAbTests, tokenSecurityTypeDestination, batchSellTrades);
626
629
  try {
627
630
  // Emit Submitted event after submit button is clicked
628
- !quoteResponse.featureId &&
629
- __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Submitted, undefined, preConfirmationProperties);
630
- // Submit non-EVM tx (Solana, BTC, Tron)
631
- if (isNonEvmChainId(quoteResponse.quote.srcChainId)) {
632
- // Handle non-EVM approval if present (e.g., Tron token approvals)
633
- if (quoteResponse.approval && isTronTrade(quoteResponse.approval)) {
634
- const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_trace, "f").call(this, getApprovalTraceParams(quoteResponse, false), async () => {
635
- return quoteResponse.approval &&
636
- isTronTrade(quoteResponse.approval)
637
- ? await handleNonEvmTx(this.messenger, quoteResponse.approval, quoteResponse, selectedAccount)
638
- : /* c8 ignore start */
639
- undefined;
640
- /* c8 ignore end */
641
- });
642
- approvalTxId = approvalTxMeta?.id;
643
- // Add delay after approval similar to EVM flow
644
- await handleApprovalDelay(quoteResponse.quote.srcChainId);
645
- }
646
- txMeta = await __classPrivateFieldGet(this, _BridgeStatusController_trace, "f").call(this, getTraceParams(quoteResponse, false), async () => {
647
- if (!(isTronTrade(quoteResponse.trade) ||
648
- isBitcoinTrade(quoteResponse.trade) ||
649
- typeof quoteResponse.trade === 'string')) {
650
- throw new Error('Failed to submit cross-chain swap transaction: trade is not a non-EVM transaction');
651
- }
652
- return await handleNonEvmTx(this.messenger, quoteResponse.trade, quoteResponse, selectedAccount);
653
- });
654
- }
655
- else {
656
- // Submit EVM tx
657
- // For hardware wallets on Mobile, this is fixes an issue where the Ledger does not get prompted for the 2nd approval
658
- // Extension does not have this issue
659
- const requireApproval = __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f") === BridgeClientId.MOBILE &&
660
- accountHardwareType !== null;
661
- // Handle smart transactions if enabled
662
- txMeta = await __classPrivateFieldGet(this, _BridgeStatusController_trace, "f").call(this, getTraceParams(quoteResponse, isStxEnabledOnClient), async () => {
663
- if (!isEvmTxData(quoteResponse.trade)) {
664
- throw new Error('Failed to submit cross-chain swap transaction: trade is not an EVM transaction');
665
- }
666
- // Check if the account is an EIP-7702 delegated account
667
- // Delegated accounts only allow 1 in-flight tx, so approve + swap
668
- // must be batched into a single transaction
669
- const hexChainId = formatChainIdToHex(quoteResponse.quote.srcChainId);
670
- isDelegatedAccount = await checkIsDelegatedAccount(this.messenger, quoteResponse.trade.from, [hexChainId]);
671
- if (isStxEnabledOnClient ||
672
- quoteResponse.quote.gasIncluded7702 ||
673
- isDelegatedAccount) {
674
- const { tradeMeta, approvalMeta } = await __classPrivateFieldGet(this, _BridgeStatusController_handleEvmTransactionBatch, "f").call(this, {
675
- isBridgeTx,
676
- quoteResponse,
677
- requireApproval,
678
- isDelegatedAccount,
679
- });
680
- approvalTxId = approvalMeta?.id;
681
- return tradeMeta;
682
- }
683
- // Set approval time and id if an approval tx is needed
684
- const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, quoteResponse, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval && isEvmTxData(quoteResponse.approval)
685
- ? quoteResponse.approval
686
- : undefined, quoteResponse.resetApproval, requireApproval);
687
- approvalTxId = approvalTxMeta?.id;
688
- // Hardware-wallet delay first (Ledger second-prompt spacing), then wait for
689
- // on-chain approval confirmation so swap gas estimation runs after allowance is set.
690
- if (requireApproval && approvalTxMeta) {
691
- await handleMobileHardwareWalletDelay(requireApproval);
692
- await waitForTxConfirmation(this.messenger, approvalTxMeta.id);
693
- }
694
- else {
695
- await handleMobileHardwareWalletDelay(requireApproval);
696
- }
697
- // Generate actionId for pre-submission history (non-batch EVM only)
698
- const actionId = generateActionId().toString();
699
- // Add pre-submission history keyed by actionId
700
- // This ensures we have quote data available if transaction fails during submission
701
- const historyKey = __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
702
- accountAddress: selectedAccount.address,
703
- quoteResponse,
704
- slippagePercentage: 0,
705
- isStxEnabled: isStxEnabledOnClient,
706
- startTime,
707
- approvalTxId,
708
- location,
709
- abTests,
710
- activeAbTests,
711
- actionId,
712
- tokenSecurityTypeDestination,
713
- });
714
- // Pass txFee when gasIncluded is true to use the quote's gas fees
715
- // instead of re-estimating (which would fail for max native token swaps)
716
- const tradeTxMeta = await submitEvmTransaction({
717
- messenger: this.messenger,
718
- transactionType: isBridgeTx
719
- ? TransactionType.bridge
720
- : TransactionType.swap,
721
- trade: quoteResponse.trade,
722
- requireApproval,
723
- txFee: quoteResponse.quote.gasIncluded
724
- ? quoteResponse.quote.feeData.txFee
725
- : undefined,
726
- actionId,
727
- });
728
- // On success, rekey from actionId to txMeta.id and update srcTxHash
729
- __classPrivateFieldGet(this, _BridgeStatusController_rekeyHistoryItem, "f").call(this, historyKey, tradeTxMeta);
730
- return tradeTxMeta;
731
- });
732
- }
631
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Submitted, undefined, preConfirmationProperties, featureId);
632
+ /**
633
+ * Check if the account is an EIP-7702 delegated account.
634
+ * Delegated accounts only allow 1 in-flight tx, so approve + swap
635
+ * must be batched into a single transaction
636
+ */
637
+ const isDelegatedAccount = isNonEvmChainId(quote.srcChainId)
638
+ ? false
639
+ : await checkIsDelegatedAccount(this.messenger, selectedAccount.address, [formatChainIdToHex(quote.srcChainId)]);
640
+ const strategyParams = {
641
+ messenger: this.messenger,
642
+ quoteResponses,
643
+ batchSellTrades,
644
+ isStxEnabled,
645
+ isBridgeTx,
646
+ isDelegatedAccount,
647
+ selectedAccount,
648
+ requireApproval,
649
+ clientId: __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"),
650
+ bridgeApiBaseUrl: __classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl,
651
+ addTransactionBatchFn: __classPrivateFieldGet(this, _BridgeStatusController_addTransactionBatchFn, "f"),
652
+ fetchFn: __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"),
653
+ traceFn: __classPrivateFieldGet(this, _BridgeStatusController_trace, "f"),
654
+ };
655
+ return await __classPrivateFieldGet(this, _BridgeStatusController_trace, "f").call(this, getTraceParams(quoteResponse, isStxEnabled), async () => await __classPrivateFieldGet(this, _BridgeStatusController_executeSubmitStrategy, "f").call(this, strategyParams, {
656
+ startTime,
657
+ location,
658
+ abTests,
659
+ activeAbTests,
660
+ tokenSecurityTypeDestination,
661
+ }));
733
662
  }
734
663
  catch (error) {
735
- !quoteResponse.featureId &&
736
- __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, undefined, {
737
- error_message: error?.message,
738
- ...preConfirmationProperties,
739
- });
664
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, undefined, {
665
+ error_message: error?.message,
666
+ ...preConfirmationProperties,
667
+ }, featureId);
740
668
  throw error;
741
669
  }
742
- try {
743
- // For non-batch EVM transactions, history was already added/rekeyed above
744
- // Only add history here for non-EVM and batch EVM transactions
745
- const isNonBatchEvm = !isNonEvmChainId(quoteResponse.quote.srcChainId) &&
746
- !isStxEnabledOnClient &&
747
- !quoteResponse.quote.gasIncluded7702 &&
748
- !isDelegatedAccount;
749
- let historyKey = txMeta.id;
750
- if (!isNonBatchEvm) {
751
- // Add swap or bridge tx to history
752
- historyKey = __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
753
- accountAddress: selectedAccount.address,
754
- bridgeTxMeta: txMeta, // Only the id and hash fields are used by the BridgeStatusController
755
- quoteResponse,
756
- slippagePercentage: 0, // TODO include slippage provided by quote if using dynamic slippage, or slippage from quote request
757
- isStxEnabled: isStxEnabledOnClient,
758
- startTime,
759
- approvalTxId,
760
- location,
761
- abTests,
762
- activeAbTests,
763
- tokenSecurityTypeDestination,
764
- });
765
- }
766
- if (isNonEvmChainId(quoteResponse.quote.srcChainId)) {
767
- // Start polling for bridge tx status
768
- __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, historyKey);
769
- // Track non-EVM Swap completed event
770
- if (!(isBridgeTx || isTronTx)) {
771
- __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Completed, historyKey);
772
- }
773
- }
774
- }
775
- catch {
776
- // Ignore errors here, we don't want to crash the app if this fails and tx submission succeeds
777
- }
778
- return txMeta;
779
670
  };
780
671
  /**
781
672
  * Submits an intent order and creates a synthetic history entry for UX.
@@ -788,135 +679,28 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
788
679
  * @param params.abTests - Legacy A/B test context for `ab_tests` (backward compatibility)
789
680
  * @param params.activeAbTests - New A/B test context for `active_ab_tests` (migration target). Attributes events to specific experiments.
790
681
  * @param params.tokenSecurityTypeDestination - The security classification of the destination token, supplied by the client (e.g. from token security/scanning data). Pass `null` when no security data is available.
682
+ * @param params.isStxEnabled - Whether smart transactions are enabled on the client, for example the getSmartTransactionsEnabled selector value from the extension
683
+ * @param params.quotesReceivedContext - The context for the QuotesReceived event
791
684
  * @returns A lightweight TransactionMeta-like object for history linking
685
+ * @throws An error if intent or transaction submission fails before they get published
792
686
  */
793
687
  this.submitIntent = async (params) => {
794
- const { quoteResponse, accountAddress, location, abTests, activeAbTests, tokenSecurityTypeDestination, } = params;
688
+ const { quoteResponse, accountAddress, location, abTests, activeAbTests, tokenSecurityTypeDestination, isStxEnabled = false, quotesReceivedContext, } = params;
795
689
  // TODO add metrics context
796
- stopPollingForQuotes(this.messenger);
797
- const startTime = Date.now();
798
- // Build pre-confirmation properties for error tracking parity with submitTx
799
- const account = getAccountByAddress(this.messenger, accountAddress);
800
- const accountHardwareType = getAccountHardwareType(account);
801
- const preConfirmationProperties = getPreConfirmationPropertiesFromQuote(quoteResponse, false, accountHardwareType, location, abTests, activeAbTests, tokenSecurityTypeDestination);
802
- try {
803
- const intent = getIntentFromQuote(quoteResponse);
804
- // If backend provided an approval tx for this intent quote, submit it first (on-chain),
805
- // then proceed with off-chain intent submission.
806
- const isBridgeTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
807
- const requireApproval = __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f") === BridgeClientId.MOBILE &&
808
- accountHardwareType !== null;
809
- // Handle approval silently for better UX in intent flows
810
- const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, quoteResponse, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval, quoteResponse.resetApproval, requireApproval);
811
- const approvalTxId = approvalTxMeta?.id;
812
- if (approvalTxId) {
813
- await waitForTxConfirmation(this.messenger, approvalTxId);
814
- }
815
- const { srcChainId, requestId } = quoteResponse.quote;
816
- const signature = await signTypedMessage({
817
- messenger: this.messenger,
818
- accountAddress,
819
- typedData: intent.typedData,
820
- });
821
- const submissionParams = {
822
- srcChainId,
823
- quoteId: requestId,
824
- signature,
825
- order: intent.order,
826
- userAddress: accountAddress,
827
- aggregatorId: intent.protocol,
828
- };
829
- const { id: orderUid, status } = await postSubmitOrder({
830
- params: submissionParams,
831
- clientId: __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"),
832
- jwt: await getJwt(this.messenger),
833
- fetchFn: __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"),
834
- bridgeApiBaseUrl: __classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl,
835
- });
836
- // Determine transaction type: swap for same-chain, bridge for cross-chain
837
- const transactionType = isBridgeTx
838
- ? /* c8 ignore start */
839
- TransactionType.bridge
840
- : /* c8 ignore end */
841
- TransactionType.swap;
842
- // Create actual transaction in Transaction Controller first
843
- const networkClientId = getNetworkClientIdByChainId(this.messenger, srcChainId);
844
- // This is a synthetic transaction whose purpose is to be able
845
- // to track the order status via the history
846
- const intentTransactionParams = {
847
- chainId: formatChainIdToHex(srcChainId),
848
- from: accountAddress,
849
- to: intent.settlementContract ??
850
- '0x9008D19f58AAbd9eD0D60971565AA8510560ab41', // Default settlement contract
851
- data: `0x${orderUid.slice(-8)}`, // Use last 8 chars of orderUid to make each transaction unique
852
- value: '0x0',
853
- gas: '0x5208', // Minimal gas for display purposes
854
- gasPrice: '0x3b9aca00', // 1 Gwei - will be converted to EIP-1559 fees if network supports it
855
- };
856
- const initialTxMeta = await addSyntheticTransaction(this.messenger, intentTransactionParams, {
857
- requireApproval: false,
858
- networkClientId,
859
- type: transactionType,
860
- });
861
- // Update txHistory with actual transaction metadata
862
- const syntheticMeta = {
863
- ...initialTxMeta,
864
- // Map intent order status to TransactionController status
865
- status: mapIntentOrderStatusToTransactionStatus(status),
866
- isIntentTx: true,
867
- orderUid,
868
- };
869
- // Record in bridge history with actual transaction metadata
870
- try {
871
- // Create a bridge transaction metadata keyed by orderUid for intent polling
872
- const bridgeTxMetaForHistory = {
873
- ...syntheticMeta,
874
- id: orderUid,
875
- };
876
- // Use orderId as the history key for intent transactions
877
- // IMPORTANT: pass originalTransactionId as a top-level argument so
878
- // `getInitialHistoryItem` reads it. Setting it on `bridgeTxMeta` is a no-op
879
- // because `getInitialHistoryItem` destructures `originalTransactionId` from
880
- // the top-level args, not from `bridgeTxMeta`. Without this, the field
881
- // falls back to `bridgeTxMeta.id` (the orderUid), severing the link between
882
- // the bridge history record and the synthetic TransactionController entry.
883
- const historyKey = __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
884
- accountAddress,
885
- bridgeTxMeta: bridgeTxMetaForHistory,
886
- originalTransactionId: syntheticMeta.id,
887
- quoteResponse,
888
- slippagePercentage: 0,
889
- isStxEnabled: false,
890
- approvalTxId,
891
- startTime,
892
- location,
893
- abTests,
894
- activeAbTests,
895
- tokenSecurityTypeDestination,
896
- });
897
- // Start polling using the orderId key to route to intent manager
898
- __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, historyKey);
899
- }
900
- catch (error) {
901
- console.error('📝 [submitIntent] Failed to add to bridge history', error);
902
- // non-fatal but log the error
903
- }
904
- return syntheticMeta;
905
- }
906
- catch (error) {
907
- __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, undefined, {
908
- error_message: error?.message,
909
- ...preConfirmationProperties,
910
- });
911
- throw error;
912
- }
690
+ return await this.submitTx(accountAddress, quoteResponse, isStxEnabled, quotesReceivedContext, location, abTests, activeAbTests, tokenSecurityTypeDestination);
691
+ };
692
+ this.submitBatchSell = async (params) => {
693
+ /**
694
+ * Retrieve the batch sell trades from the BridgeController's state to ensure we submit
695
+ * the original response data from the bridge-api
696
+ */
697
+ const batchSellTrades = getBatchSellTrades(this.messenger);
698
+ return await this.submitTx(params.accountAddress, params.quoteResponses.filter((quoteResponse) => quoteResponse !== null), params.isStxEnabled ?? false, params.quotesReceivedContext, params.location, params.abTests, params.activeAbTests, params.tokenSecurityTypeDestination, batchSellTrades);
913
699
  };
914
700
  _BridgeStatusController_trackPollingStatusUpdatedEvent.set(this, (historyKey, pollingStatus) => {
915
701
  // Track polling status updated event
916
702
  const historyItem = this.state.txHistory[historyKey];
917
- if (historyItem && !historyItem.featureId) {
918
- __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.PollingStatusUpdated, historyKey, getPollingStatusUpdatedProperties(this.messenger, pollingStatus, historyItem));
919
- }
703
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.PollingStatusUpdated, historyKey, getPollingStatusUpdatedProperties(this.messenger, pollingStatus, historyItem));
920
704
  });
921
705
  /**
922
706
  * Tracks post-submission events for a cross-chain swap based on the history item
@@ -924,8 +708,22 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
924
708
  * @param eventName - The name of the event to track
925
709
  * @param txMetaId - The txMetaId of the history item to track the event for
926
710
  * @param eventProperties - The properties for the event
711
+ * @param featureIdOverride - The featureId to use when the history item is not available. Should
712
+ * only be provided for events that are not associated with a history item yet, such as Submitted or Failed
927
713
  */
928
- _BridgeStatusController_trackUnifiedSwapBridgeEvent.set(this, (eventName, txMetaId, eventProperties) => {
714
+ _BridgeStatusController_trackUnifiedSwapBridgeEvent.set(this, (eventName, txMetaId, eventProperties, featureIdOverride) => {
715
+ const historyItem = txMetaId
716
+ ? this.state.txHistory[txMetaId]
717
+ : undefined;
718
+ const featureId = featureIdOverride ?? historyItem?.featureId;
719
+ const shouldSkipMetrics =
720
+ // Skip tracking all other events when featureId is set (i.e. PERPS)
721
+ featureId &&
722
+ // Always publish StatusValidationFailed event, regardless of featureId
723
+ eventName !== UnifiedSwapBridgeEventName.StatusValidationFailed;
724
+ if (shouldSkipMetrics) {
725
+ return;
726
+ }
929
727
  // Legacy/new metrics fields are intentionally kept independent during migration.
930
728
  const historyAbTests = txMetaId
931
729
  ? this.state.txHistory?.[txMetaId]?.abTests
@@ -935,12 +733,12 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
935
733
  : undefined;
936
734
  const resolvedAbTests = eventProperties?.ab_tests ?? historyAbTests;
937
735
  const resolvedActiveAbTests = eventProperties?.active_ab_tests ?? historyActiveAbTests;
736
+ const location = (txMetaId ? this.state.txHistory?.[txMetaId]?.location : undefined) ??
737
+ MetaMetricsSwapsEventSource.MainView;
938
738
  const baseProperties = {
939
739
  action_type: MetricsActionType.SWAPBRIDGE_V1,
940
- location: eventProperties?.location ??
941
- (txMetaId ? this.state.txHistory?.[txMetaId]?.location : undefined) ??
942
- MetaMetricsSwapsEventSource.MainView,
943
740
  ...(eventProperties ?? {}),
741
+ location,
944
742
  ...(resolvedAbTests &&
945
743
  Object.keys(resolvedAbTests).length > 0 && {
946
744
  ab_tests: resolvedAbTests,
@@ -951,15 +749,6 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
951
749
  }),
952
750
  };
953
751
  // This will publish events for PERPS dropped tx failures as well
954
- if (!txMetaId) {
955
- trackMetricsEvent({
956
- messenger: this.messenger,
957
- eventName,
958
- properties: baseProperties,
959
- });
960
- return;
961
- }
962
- const historyItem = this.state.txHistory[txMetaId];
963
752
  if (!historyItem) {
964
753
  trackMetricsEvent({
965
754
  messenger: this.messenger,
@@ -968,9 +757,8 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
968
757
  });
969
758
  return;
970
759
  }
971
- const { featureId, approvalTxId, quote } = historyItem;
760
+ const { approvalTxId, quote } = historyItem;
972
761
  const requestParamProperties = getRequestParamFromHistory(historyItem);
973
- // Always publish StatusValidationFailed event, regardless of featureId
974
762
  if (eventName === UnifiedSwapBridgeEventName.StatusValidationFailed) {
975
763
  trackMetricsEvent({
976
764
  messenger: this.messenger,
@@ -987,10 +775,6 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
987
775
  });
988
776
  return;
989
777
  }
990
- // Skip tracking all other events when featureId is set (i.e. PERPS)
991
- if (featureId) {
992
- return;
993
- }
994
778
  const selectedAccount = getAccountByAddress(this.messenger, historyItem.account);
995
779
  const transactions = getTransactions(this.messenger);
996
780
  const txMeta = transactions.find((tx) => tx.id === txMetaId);
@@ -1070,5 +854,5 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
1070
854
  __classPrivateFieldGet(this, _BridgeStatusController_restartPollingForIncompleteHistoryItems, "f").call(this);
1071
855
  }
1072
856
  }
1073
- _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_intentManager = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_addTransactionBatchFn = new WeakMap(), _BridgeStatusController_trace = new WeakMap(), _BridgeStatusController_onTransactionFailed = new WeakMap(), _BridgeStatusController_onTransactionConfirmed = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_addTxToHistory = new WeakMap(), _BridgeStatusController_rekeyHistoryItem = new WeakMap(), _BridgeStatusController_startPollingForTxId = new WeakMap(), _BridgeStatusController_handleFetchFailure = new WeakMap(), _BridgeStatusController_handleOldHistoryItem = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_setAndGetSrcTxHash = new WeakMap(), _BridgeStatusController_updateHistoryItem = new WeakMap(), _BridgeStatusController_deleteHistoryItem = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_handleApprovalTx = new WeakMap(), _BridgeStatusController_handleEvmTransactionBatch = new WeakMap(), _BridgeStatusController_trackPollingStatusUpdatedEvent = new WeakMap(), _BridgeStatusController_trackUnifiedSwapBridgeEvent = new WeakMap();
857
+ _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_intentManager = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_addTransactionBatchFn = new WeakMap(), _BridgeStatusController_trace = new WeakMap(), _BridgeStatusController_onTransactionFailed = new WeakMap(), _BridgeStatusController_onTransactionConfirmed = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_addTxToHistory = new WeakMap(), _BridgeStatusController_rekeyHistoryItem = new WeakMap(), _BridgeStatusController_startPollingForTxId = new WeakMap(), _BridgeStatusController_handleFetchFailure = new WeakMap(), _BridgeStatusController_handleOldHistoryItem = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_setAndGetSrcTxHash = new WeakMap(), _BridgeStatusController_updateHistoryItem = new WeakMap(), _BridgeStatusController_deleteHistoryItem = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_executeSubmitStrategy = new WeakMap(), _BridgeStatusController_trackPollingStatusUpdatedEvent = new WeakMap(), _BridgeStatusController_trackUnifiedSwapBridgeEvent = new WeakMap();
1074
858
  //# sourceMappingURL=bridge-status-controller.mjs.map