@metamask/bridge-status-controller 68.0.2 → 69.0.0

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 (70) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/dist/bridge-status-controller.cjs +73 -42
  3. package/dist/bridge-status-controller.cjs.map +1 -1
  4. package/dist/bridge-status-controller.d.cts +12 -3
  5. package/dist/bridge-status-controller.d.cts.map +1 -1
  6. package/dist/bridge-status-controller.d.mts +12 -3
  7. package/dist/bridge-status-controller.d.mts.map +1 -1
  8. package/dist/bridge-status-controller.intent.cjs +3 -6
  9. package/dist/bridge-status-controller.intent.cjs.map +1 -1
  10. package/dist/bridge-status-controller.intent.d.cts +4 -3
  11. package/dist/bridge-status-controller.intent.d.cts.map +1 -1
  12. package/dist/bridge-status-controller.intent.d.mts +4 -3
  13. package/dist/bridge-status-controller.intent.d.mts.map +1 -1
  14. package/dist/bridge-status-controller.intent.mjs +4 -7
  15. package/dist/bridge-status-controller.intent.mjs.map +1 -1
  16. package/dist/bridge-status-controller.mjs +73 -42
  17. package/dist/bridge-status-controller.mjs.map +1 -1
  18. package/dist/types.cjs.map +1 -1
  19. package/dist/types.d.cts +13 -3
  20. package/dist/types.d.cts.map +1 -1
  21. package/dist/types.d.mts +13 -3
  22. package/dist/types.d.mts.map +1 -1
  23. package/dist/types.mjs.map +1 -1
  24. package/dist/utils/bridge-status.cjs +2 -4
  25. package/dist/utils/bridge-status.cjs.map +1 -1
  26. package/dist/utils/bridge-status.d.cts.map +1 -1
  27. package/dist/utils/bridge-status.d.mts.map +1 -1
  28. package/dist/utils/bridge-status.mjs +2 -4
  29. package/dist/utils/bridge-status.mjs.map +1 -1
  30. package/dist/utils/gas.cjs +2 -2
  31. package/dist/utils/gas.cjs.map +1 -1
  32. package/dist/utils/gas.d.cts +1 -1
  33. package/dist/utils/gas.d.cts.map +1 -1
  34. package/dist/utils/gas.d.mts +1 -1
  35. package/dist/utils/gas.d.mts.map +1 -1
  36. package/dist/utils/gas.mjs +2 -2
  37. package/dist/utils/gas.mjs.map +1 -1
  38. package/dist/utils/intent-api.cjs +2 -2
  39. package/dist/utils/intent-api.cjs.map +1 -1
  40. package/dist/utils/intent-api.d.cts +8 -7
  41. package/dist/utils/intent-api.d.cts.map +1 -1
  42. package/dist/utils/intent-api.d.mts +8 -7
  43. package/dist/utils/intent-api.d.mts.map +1 -1
  44. package/dist/utils/intent-api.mjs +4 -4
  45. package/dist/utils/intent-api.mjs.map +1 -1
  46. package/dist/utils/metrics.cjs +11 -3
  47. package/dist/utils/metrics.cjs.map +1 -1
  48. package/dist/utils/metrics.d.cts +10 -2
  49. package/dist/utils/metrics.d.cts.map +1 -1
  50. package/dist/utils/metrics.d.mts +10 -2
  51. package/dist/utils/metrics.d.mts.map +1 -1
  52. package/dist/utils/metrics.mjs +11 -3
  53. package/dist/utils/metrics.mjs.map +1 -1
  54. package/dist/utils/transaction.cjs +23 -14
  55. package/dist/utils/transaction.cjs.map +1 -1
  56. package/dist/utils/transaction.d.cts +4 -2
  57. package/dist/utils/transaction.d.cts.map +1 -1
  58. package/dist/utils/transaction.d.mts +4 -2
  59. package/dist/utils/transaction.d.mts.map +1 -1
  60. package/dist/utils/transaction.mjs +23 -14
  61. package/dist/utils/transaction.mjs.map +1 -1
  62. package/dist/utils/validators.cjs +5 -5
  63. package/dist/utils/validators.cjs.map +1 -1
  64. package/dist/utils/validators.d.cts +5 -10
  65. package/dist/utils/validators.d.cts.map +1 -1
  66. package/dist/utils/validators.d.mts +5 -10
  67. package/dist/utils/validators.d.mts.map +1 -1
  68. package/dist/utils/validators.mjs +3 -3
  69. package/dist/utils/validators.mjs.map +1 -1
  70. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [69.0.0]
11
+
12
+ ### Added
13
+
14
+ - Added more unit test coverage for intents and EVM transactions. Also refactored some mocks and code blocks to improve testability ([#8186](https://github.com/MetaMask/core/pull/8186))
15
+
16
+ ### Changed
17
+
18
+ - Bump `@metamask/bridge-controller` from `^69.1.0` to `^69.1.1` ([#8225](https://github.com/MetaMask/core/pull/8225))
19
+ - Bump `@metamask/gas-fee-controller` from `^26.0.3` to `^26.1.0` ([#8225](https://github.com/MetaMask/core/pull/8225))
20
+ - **BREAKING:** `BridgeStatusControllerMessenger` must now allow `TransactionController:isAtomicBatchSupported` action ([#8125](https://github.com/MetaMask/core/pull/8125))
21
+ - Bump `@metamask/transaction-controller` from `^62.21.0` to `^63.0.0` ([#8217](https://github.com/MetaMask/core/pull/8217), [#8225](https://github.com/MetaMask/core/pull/8225))
22
+
23
+ ### Fixed
24
+
25
+ - Delegated accounts (EIP-7702) now use batched transactions to avoid in-flight transaction limit ([#8125](https://github.com/MetaMask/core/pull/8125))
26
+ - Bridge transaction types now properly matched in 7702 batch path ([#8125](https://github.com/MetaMask/core/pull/8125))
27
+ - Delegated account batch transactions now recorded in bridge status history ([#8125](https://github.com/MetaMask/core/pull/8125))
28
+ - Gas fields now included for delegated account transactions that are not gas-sponsored ([#8125](https://github.com/MetaMask/core/pull/8125))
29
+
30
+ ## [68.1.0]
31
+
32
+ ### Added
33
+
34
+ - Added optional `activeAbTests` context support so Unified SwapBridge events can include `active_ab_tests` independently of `ab_tests`. ([#8152](https://github.com/MetaMask/core/pull/8152))
35
+
36
+ ### Changed
37
+
38
+ - Bump `@metamask/bridge-controller` from `^69.0.1` to `^69.1.0` ([#8168](https://github.com/MetaMask/core/pull/8168))
39
+
10
40
  ## [68.0.2]
11
41
 
12
42
  ### Changed
@@ -1010,7 +1040,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
1040
 
1011
1041
  - Initial release ([#5317](https://github.com/MetaMask/core/pull/5317))
1012
1042
 
1013
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@68.0.2...HEAD
1043
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@69.0.0...HEAD
1044
+ [69.0.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@68.1.0...@metamask/bridge-status-controller@69.0.0
1045
+ [68.1.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@68.0.2...@metamask/bridge-status-controller@68.1.0
1014
1046
  [68.0.2]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@68.0.1...@metamask/bridge-status-controller@68.0.2
1015
1047
  [68.0.1]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@68.0.0...@metamask/bridge-status-controller@68.0.1
1016
1048
  [68.0.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@67.0.1...@metamask/bridge-status-controller@68.0.0
@@ -208,7 +208,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
208
208
  });
209
209
  });
210
210
  _BridgeStatusController_addTxToHistory.set(this, (startPollingForBridgeTxStatusArgs, actionId) => {
211
- const { bridgeTxMeta, statusRequest, quoteResponse, startTime, slippagePercentage, initialDestAssetBalance, targetContractAddress, approvalTxId, isStxEnabled, location, abTests, accountAddress: selectedAddress, } = startPollingForBridgeTxStatusArgs;
211
+ const { bridgeTxMeta, statusRequest, quoteResponse, startTime, slippagePercentage, initialDestAssetBalance, targetContractAddress, approvalTxId, isStxEnabled, location, abTests, activeAbTests, accountAddress: selectedAddress, } = startPollingForBridgeTxStatusArgs;
212
212
  // Determine the key for this history item:
213
213
  // - For pre-submission (non-batch EVM): use actionId
214
214
  // - For post-submission or other cases: use bridgeTxMeta.id
@@ -246,10 +246,11 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
246
246
  },
247
247
  hasApprovalTx: Boolean(quoteResponse.approval),
248
248
  approvalTxId,
249
- isStxEnabled: isStxEnabled ?? false,
249
+ isStxEnabled: Boolean(isStxEnabled),
250
250
  featureId: quoteResponse.featureId,
251
251
  location,
252
252
  ...(abTests && { abTests }),
253
+ ...(activeAbTests && { activeAbTests }),
253
254
  };
254
255
  this.update((state) => {
255
256
  // Use actionId as key for pre-submission, or txMeta.id for post-submission
@@ -381,9 +382,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
381
382
  try {
382
383
  let status;
383
384
  let validationFailures = [];
384
- const isIntent = Boolean(historyItem.quote.intent);
385
- if (isIntent) {
386
- const intentTxStatus = await __classPrivateFieldGet(this, _BridgeStatusController_intentManager, "f").getIntentTransactionStatus(bridgeTxMetaId, historyItem, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
385
+ if (historyItem.quote.intent) {
386
+ const intentTxStatus = await __classPrivateFieldGet(this, _BridgeStatusController_intentManager, "f").getIntentTransactionStatus(bridgeTxMetaId, historyItem.quote.srcChainId, historyItem.quote.intent.protocol, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"), historyItem.status.srcChain.txHash);
387
387
  if (intentTxStatus?.bridgeStatus === null ||
388
388
  intentTxStatus?.bridgeStatus === undefined) {
389
389
  return;
@@ -428,7 +428,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
428
428
  this.update((state) => {
429
429
  state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;
430
430
  });
431
- if (isIntent) {
431
+ if (historyItem.quote.intent) {
432
432
  __classPrivateFieldGet(this, _BridgeStatusController_intentManager, "f").syncTransactionFromIntentStatus(bridgeTxMetaId, historyItem);
433
433
  }
434
434
  // 5. After effects
@@ -562,7 +562,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
562
562
  });
563
563
  });
564
564
  _BridgeStatusController_handleApprovalTx.set(this, async (isBridgeTx, srcChainId, approval, resetApproval, requireApproval) => {
565
- if (approval) {
565
+ if (approval && (0, bridge_controller_1.isEvmTxData)(approval)) {
566
566
  const approveTx = async () => {
567
567
  await __classPrivateFieldGet(this, _BridgeStatusController_handleUSDTAllowanceReset, "f").call(this, resetApproval);
568
568
  const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleEvmTransaction, "f").call(this, {
@@ -649,8 +649,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
649
649
  // Convert to hex since txFee values from the quote are decimal strings
650
650
  if (txFee) {
651
651
  return {
652
- maxFeePerGas: (0, controller_utils_1.toHex)(txFee.maxFeePerGas ?? 0),
653
- maxPriorityFeePerGas: (0, controller_utils_1.toHex)(txFee.maxPriorityFeePerGas ?? 0),
652
+ maxFeePerGas: (0, controller_utils_1.toHex)(txFee.maxFeePerGas),
653
+ maxPriorityFeePerGas: (0, controller_utils_1.toHex)(txFee.maxPriorityFeePerGas),
654
654
  gas: gas ? (0, controller_utils_1.toHex)(gas) : undefined,
655
655
  };
656
656
  }
@@ -714,10 +714,11 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
714
714
  * @param isStxEnabledOnClient - Whether smart transactions are enabled on the client, for example the getSmartTransactionsEnabled selector value from the extension
715
715
  * @param quotesReceivedContext - The context for the QuotesReceived event
716
716
  * @param location - The entry point from which the user initiated the swap or bridge (e.g. Main View, Token View, Trending Explore)
717
- * @param abTests - A/B test context to attribute events to specific experiments
717
+ * @param abTests - Legacy A/B test context for `ab_tests` (backward compatibility)
718
+ * @param activeAbTests - New A/B test context for `active_ab_tests` (migration target). Attributes events to specific experiments.
718
719
  * @returns The transaction meta
719
720
  */
720
- this.submitTx = async (accountAddress, quoteResponse, isStxEnabledOnClient, quotesReceivedContext, location = bridge_controller_1.MetaMetricsSwapsEventSource.MainView, abTests) => {
721
+ this.submitTx = async (accountAddress, quoteResponse, isStxEnabledOnClient, quotesReceivedContext, location = bridge_controller_1.MetaMetricsSwapsEventSource.MainView, abTests, activeAbTests) => {
721
722
  this.messenger.call('BridgeController:stopPollingForQuotes', bridge_controller_1.AbortReason.TransactionSubmitted,
722
723
  // If trade is submitted before all quotes are loaded, the QuotesReceived event is published
723
724
  // If the trade has a featureId, it means it was submitted outside of the Unified Swap and Bridge experience, so no QuotesReceived event is published
@@ -727,12 +728,13 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
727
728
  throw new Error('Failed to submit cross-chain swap transaction: undefined multichain account');
728
729
  }
729
730
  const isHardwareAccount = (0, bridge_controller_1.isHardwareWallet)(selectedAccount);
730
- const preConfirmationProperties = (0, metrics_1.getPreConfirmationPropertiesFromQuote)(quoteResponse, isStxEnabledOnClient, isHardwareAccount, location, abTests);
731
+ const preConfirmationProperties = (0, metrics_1.getPreConfirmationPropertiesFromQuote)(quoteResponse, isStxEnabledOnClient, isHardwareAccount, location, abTests, activeAbTests);
731
732
  // Emit Submitted event after submit button is clicked
732
733
  !quoteResponse.featureId &&
733
734
  __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Submitted, undefined, preConfirmationProperties);
734
735
  let txMeta;
735
736
  let approvalTxId;
737
+ let isDelegatedAccount = false;
736
738
  const startTime = Date.now();
737
739
  const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
738
740
  const isTronTx = (0, bridge_controller_1.isTronChainId)(quoteResponse.quote.srcChainId);
@@ -753,7 +755,9 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
753
755
  return quoteResponse.approval &&
754
756
  (0, bridge_controller_1.isTronTrade)(quoteResponse.approval)
755
757
  ? await __classPrivateFieldGet(this, _BridgeStatusController_handleNonEvmTx, "f").call(this, quoteResponse.approval, quoteResponse, selectedAccount)
756
- : undefined;
758
+ : /* c8 ignore start */
759
+ undefined;
760
+ /* c8 ignore end */
757
761
  }
758
762
  catch (error) {
759
763
  !quoteResponse.featureId &&
@@ -787,7 +791,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
787
791
  }
788
792
  catch (error) {
789
793
  !quoteResponse.featureId &&
790
- __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Failed, txMeta?.id, {
794
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Failed, undefined, {
791
795
  error_message: error?.message,
792
796
  ...preConfirmationProperties,
793
797
  });
@@ -813,7 +817,25 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
813
817
  if (!(0, bridge_controller_1.isEvmTxData)(quoteResponse.trade)) {
814
818
  throw new Error('Failed to submit cross-chain swap transaction: trade is not an EVM transaction');
815
819
  }
816
- if (isStxEnabledOnClient || quoteResponse.quote.gasIncluded7702) {
820
+ // Check if the account is an EIP-7702 delegated account
821
+ // Delegated accounts only allow 1 in-flight tx, so approve + swap
822
+ // must be batched into a single transaction
823
+ const hexChainId = (0, bridge_controller_1.formatChainIdToHex)(quoteResponse.quote.srcChainId);
824
+ isDelegatedAccount = await (async () => {
825
+ try {
826
+ const atomicBatchSupport = await this.messenger.call('TransactionController:isAtomicBatchSupported', {
827
+ address: quoteResponse.trade.from,
828
+ chainIds: [hexChainId],
829
+ });
830
+ return atomicBatchSupport.some((entry) => entry.isSupported && entry.delegationAddress);
831
+ }
832
+ catch {
833
+ return false;
834
+ }
835
+ })();
836
+ if (isStxEnabledOnClient ||
837
+ quoteResponse.quote.gasIncluded7702 ||
838
+ isDelegatedAccount) {
817
839
  const { tradeMeta, approvalMeta } = await __classPrivateFieldGet(this, _BridgeStatusController_handleEvmTransactionBatch, "f").call(this, {
818
840
  isBridgeTx,
819
841
  resetApproval: quoteResponse.resetApproval,
@@ -823,6 +845,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
823
845
  trade: quoteResponse.trade,
824
846
  quoteResponse,
825
847
  requireApproval,
848
+ isDelegatedAccount,
826
849
  });
827
850
  approvalTxId = approvalMeta?.id;
828
851
  return tradeMeta;
@@ -850,6 +873,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
850
873
  approvalTxId,
851
874
  location,
852
875
  abTests,
876
+ activeAbTests,
853
877
  }, actionId);
854
878
  // Pass txFee when gasIncluded is true to use the quote's gas fees
855
879
  // instead of re-estimating (which would fail for max native token swaps)
@@ -874,7 +898,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
874
898
  // Only add history here for non-EVM and batch EVM transactions
875
899
  const isNonBatchEvm = !(0, bridge_controller_1.isNonEvmChainId)(quoteResponse.quote.srcChainId) &&
876
900
  !isStxEnabledOnClient &&
877
- !quoteResponse.quote.gasIncluded7702;
901
+ !quoteResponse.quote.gasIncluded7702 &&
902
+ !isDelegatedAccount;
878
903
  if (!isNonBatchEvm) {
879
904
  // Add swap or bridge tx to history
880
905
  __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
@@ -891,6 +916,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
891
916
  approvalTxId,
892
917
  location,
893
918
  abTests,
919
+ activeAbTests,
894
920
  });
895
921
  }
896
922
  if ((0, bridge_controller_1.isNonEvmChainId)(quoteResponse.quote.srcChainId)) {
@@ -915,40 +941,36 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
915
941
  * @param params.quoteResponse - Quote carrying intent data
916
942
  * @param params.accountAddress - The EOA submitting the order
917
943
  * @param params.location - The entry point from which the user initiated the swap or bridge
918
- * @param params.abTests - A/B test context to attribute events to specific experiments
944
+ * @param params.abTests - Legacy A/B test context for `ab_tests` (backward compatibility)
945
+ * @param params.activeAbTests - New A/B test context for `active_ab_tests` (migration target). Attributes events to specific experiments.
919
946
  * @returns A lightweight TransactionMeta-like object for history linking
920
947
  */
921
948
  this.submitIntent = async (params) => {
922
- const { quoteResponse, accountAddress, location, abTests } = params;
949
+ const { quoteResponse, accountAddress, location, abTests, activeAbTests } = params;
923
950
  this.messenger.call('BridgeController:stopPollingForQuotes', bridge_controller_1.AbortReason.TransactionSubmitted);
924
951
  // Build pre-confirmation properties for error tracking parity with submitTx
925
952
  const account = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this, accountAddress);
926
953
  const isHardwareAccount = Boolean(account) && (0, bridge_controller_1.isHardwareWallet)(account);
927
- const preConfirmationProperties = (0, metrics_1.getPreConfirmationPropertiesFromQuote)(quoteResponse, false, isHardwareAccount, location, abTests);
954
+ const preConfirmationProperties = (0, metrics_1.getPreConfirmationPropertiesFromQuote)(quoteResponse, false, isHardwareAccount, location, abTests, activeAbTests);
928
955
  try {
929
956
  const intent = (0, transaction_1.getIntentFromQuote)(quoteResponse);
930
957
  // If backend provided an approval tx for this intent quote, submit it first (on-chain),
931
958
  // then proceed with off-chain intent submission.
932
- let approvalTxId;
933
- if (quoteResponse.approval) {
934
- const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
935
- // Handle approval silently for better UX in intent flows
936
- const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval && (0, bridge_controller_1.isEvmTxData)(quoteResponse.approval)
937
- ? quoteResponse.approval
938
- : undefined, quoteResponse.resetApproval,
939
- /* requireApproval */ false);
940
- approvalTxId = approvalTxMeta?.id;
941
- if (approvalTxId) {
942
- await __classPrivateFieldGet(this, _BridgeStatusController_waitForTxConfirmation, "f").call(this, approvalTxId);
943
- }
959
+ const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
960
+ const requireApproval = isHardwareAccount && __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f") === types_1.BridgeClientId.MOBILE;
961
+ // Handle approval silently for better UX in intent flows
962
+ const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval, quoteResponse.resetApproval, requireApproval);
963
+ const approvalTxId = approvalTxMeta?.id;
964
+ if (approvalTxId) {
965
+ await __classPrivateFieldGet(this, _BridgeStatusController_waitForTxConfirmation, "f").call(this, approvalTxId);
944
966
  }
945
- const { srcChainId: chainId, requestId } = quoteResponse.quote;
967
+ const { srcChainId, requestId } = quoteResponse.quote;
946
968
  const signature = await this.messenger.call('KeyringController:signTypedMessage', {
947
969
  from: accountAddress,
948
970
  data: intent.typedData,
949
971
  }, keyring_controller_1.SignTypedDataVersion.V4);
950
972
  const submissionParams = {
951
- srcChainId: chainId.toString(),
973
+ srcChainId,
952
974
  quoteId: requestId,
953
975
  signature,
954
976
  order: intent.order,
@@ -958,16 +980,17 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
958
980
  const intentOrder = await __classPrivateFieldGet(this, _BridgeStatusController_intentManager, "f").submitIntent(submissionParams, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
959
981
  const orderUid = intentOrder.id;
960
982
  // Determine transaction type: swap for same-chain, bridge for cross-chain
961
- const isCrossChainTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
962
- const transactionType = isCrossChainTx
963
- ? transaction_controller_1.TransactionType.bridge
964
- : transaction_controller_1.TransactionType.swap;
983
+ const transactionType = isBridgeTx
984
+ ? /* c8 ignore start */
985
+ transaction_controller_1.TransactionType.bridge
986
+ : /* c8 ignore end */
987
+ transaction_controller_1.TransactionType.swap;
965
988
  // Create actual transaction in Transaction Controller first
966
- const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', (0, bridge_controller_1.formatChainIdToHex)(chainId));
989
+ const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', (0, bridge_controller_1.formatChainIdToHex)(srcChainId));
967
990
  // This is a synthetic transaction whose purpose is to be able
968
991
  // to track the order status via the history
969
992
  const intentTransactionParams = {
970
- chainId: (0, bridge_controller_1.formatChainIdToHex)(chainId),
993
+ chainId: (0, bridge_controller_1.formatChainIdToHex)(srcChainId),
971
994
  from: accountAddress,
972
995
  to: intent.settlementContract ??
973
996
  '0x9008D19f58AAbd9eD0D60971565AA8510560ab41', // Default settlement contract
@@ -997,7 +1020,6 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
997
1020
  ...statusUpdatedTxMeta,
998
1021
  isIntentTx: true,
999
1022
  orderUid,
1000
- intentType: isCrossChainTx ? 'bridge' : 'swap',
1001
1023
  };
1002
1024
  // Record in bridge history with actual transaction metadata
1003
1025
  try {
@@ -1024,6 +1046,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
1024
1046
  startTime,
1025
1047
  location,
1026
1048
  abTests,
1049
+ activeAbTests,
1027
1050
  });
1028
1051
  // Start polling using the orderId key to route to intent manager
1029
1052
  __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, bridgeHistoryKey);
@@ -1050,11 +1073,15 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
1050
1073
  * @param eventProperties - The properties for the event
1051
1074
  */
1052
1075
  _BridgeStatusController_trackUnifiedSwapBridgeEvent.set(this, (eventName, txMetaId, eventProperties) => {
1053
- const { ab_tests: eventAbTests } = eventProperties ?? {};
1076
+ // Legacy/new metrics fields are intentionally kept independent during migration.
1054
1077
  const historyAbTests = txMetaId
1055
1078
  ? this.state.txHistory?.[txMetaId]?.abTests
1056
1079
  : undefined;
1057
- const resolvedAbTests = eventAbTests ?? historyAbTests ?? undefined;
1080
+ const historyActiveAbTests = txMetaId
1081
+ ? this.state.txHistory?.[txMetaId]?.activeAbTests
1082
+ : undefined;
1083
+ const resolvedAbTests = eventProperties?.ab_tests ?? historyAbTests;
1084
+ const resolvedActiveAbTests = eventProperties?.active_ab_tests ?? historyActiveAbTests;
1058
1085
  const baseProperties = {
1059
1086
  action_type: bridge_controller_1.MetricsActionType.SWAPBRIDGE_V1,
1060
1087
  location: eventProperties?.location ??
@@ -1065,6 +1092,10 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
1065
1092
  Object.keys(resolvedAbTests).length > 0 && {
1066
1093
  ab_tests: resolvedAbTests,
1067
1094
  }),
1095
+ ...(resolvedActiveAbTests &&
1096
+ resolvedActiveAbTests.length > 0 && {
1097
+ active_ab_tests: resolvedActiveAbTests,
1098
+ }),
1068
1099
  };
1069
1100
  // This will publish events for PERPS dropped tx failures as well
1070
1101
  if (!txMetaId) {