@metamask/bridge-status-controller 64.3.0 → 64.4.1

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 (44) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/dist/bridge-status-controller.cjs +344 -18
  3. package/dist/bridge-status-controller.cjs.map +1 -1
  4. package/dist/bridge-status-controller.d.cts +16 -1
  5. package/dist/bridge-status-controller.d.cts.map +1 -1
  6. package/dist/bridge-status-controller.d.mts +16 -1
  7. package/dist/bridge-status-controller.d.mts.map +1 -1
  8. package/dist/bridge-status-controller.mjs +344 -18
  9. package/dist/bridge-status-controller.mjs.map +1 -1
  10. package/dist/types.cjs +9 -7
  11. package/dist/types.cjs.map +1 -1
  12. package/dist/types.d.cts +26 -16
  13. package/dist/types.d.cts.map +1 -1
  14. package/dist/types.d.mts +26 -16
  15. package/dist/types.d.mts.map +1 -1
  16. package/dist/types.mjs +9 -7
  17. package/dist/types.mjs.map +1 -1
  18. package/dist/utils/gas.cjs +2 -1
  19. package/dist/utils/gas.cjs.map +1 -1
  20. package/dist/utils/gas.d.cts.map +1 -1
  21. package/dist/utils/gas.d.mts.map +1 -1
  22. package/dist/utils/gas.mjs +2 -1
  23. package/dist/utils/gas.mjs.map +1 -1
  24. package/dist/utils/intent-api.cjs +90 -0
  25. package/dist/utils/intent-api.cjs.map +1 -0
  26. package/dist/utils/intent-api.d.cts +26 -0
  27. package/dist/utils/intent-api.d.cts.map +1 -0
  28. package/dist/utils/intent-api.d.mts +26 -0
  29. package/dist/utils/intent-api.d.mts.map +1 -0
  30. package/dist/utils/intent-api.mjs +84 -0
  31. package/dist/utils/intent-api.mjs.map +1 -0
  32. package/dist/utils/transaction.d.cts +21 -2
  33. package/dist/utils/transaction.d.cts.map +1 -1
  34. package/dist/utils/transaction.d.mts +21 -2
  35. package/dist/utils/transaction.d.mts.map +1 -1
  36. package/dist/utils/validators.cjs +23 -1
  37. package/dist/utils/validators.cjs.map +1 -1
  38. package/dist/utils/validators.d.cts +51 -0
  39. package/dist/utils/validators.d.cts.map +1 -1
  40. package/dist/utils/validators.d.mts +51 -0
  41. package/dist/utils/validators.d.mts.map +1 -1
  42. package/dist/utils/validators.mjs +22 -1
  43. package/dist/utils/validators.mjs.map +1 -1
  44. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -7,10 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [64.4.1]
11
+
12
+ ### Fixed
13
+
14
+ - Use `BRIDGE_PREFERRED_GAS_ESTIMATE` from `@metamask/bridge-controller` for gas price estimates to align with validation ([#7582](https://github.com/MetaMask/core/pull/7582))
15
+
16
+ ## [64.4.0]
17
+
18
+ ### Added
19
+
20
+ - Add intent based transaction support ([#6547](https://github.com/MetaMask/core/pull/6547))
21
+
22
+ ### Changed
23
+
24
+ - Bump `@metamask/transaction-controller` from `^62.7.0` to `^62.8.0` ([#7596](https://github.com/MetaMask/core/pull/7596))
25
+ - Bump `@metamask/bridge-controller` from `^64.3.0` to `^64.4.0` ([#7596](https://github.com/MetaMask/core/pull/7596))
26
+ - Bump `@metamask/controller-utils` from `^11.17.0` to `^11.18.0` ([#7583](https://github.com/MetaMask/core/pull/7583))
27
+ - Bump `@metamask/network-controller` from `^27.1.0` to `^27.2.0` ([#7583](https://github.com/MetaMask/core/pull/7583))
28
+
10
29
  ## [64.3.0]
11
30
 
12
31
  ### Changed
13
32
 
33
+ - **BREAKING** Use CrossChain API instead of the intent manager package for intent order submission ([#6547](https://github.com/MetaMask/core/pull/6547))
14
34
  - Bump `@metamask/snaps-controllers` from `^14.0.1` to `^17.2.0` ([#7550](https://github.com/MetaMask/core/pull/7550))
15
35
  - Upgrade `@metamask/utils` from `^11.8.1` to `^11.9.0` ([#7511](https://github.com/MetaMask/core/pull/7511))
16
36
  - Bump `@metamask/network-controller` from `^27.0.0` to `^27.1.0` ([#7534](https://github.com/MetaMask/core/pull/7534))
@@ -839,7 +859,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
839
859
 
840
860
  - Initial release ([#5317](https://github.com/MetaMask/core/pull/5317))
841
861
 
842
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.3.0...HEAD
862
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.4.1...HEAD
863
+ [64.4.1]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.4.0...@metamask/bridge-status-controller@64.4.1
864
+ [64.4.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.3.0...@metamask/bridge-status-controller@64.4.0
843
865
  [64.3.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.2.0...@metamask/bridge-status-controller@64.3.0
844
866
  [64.2.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.1.0...@metamask/bridge-status-controller@64.2.0
845
867
  [64.1.0]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@64.0.1...@metamask/bridge-status-controller@64.1.0
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  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");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_addTransactionFn, _BridgeStatusController_addTransactionBatchFn, _BridgeStatusController_updateTransactionFn, _BridgeStatusController_estimateGasFeeFn, _BridgeStatusController_trace, _BridgeStatusController_markTxAsFailed, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_addTxToHistory, _BridgeStatusController_startPollingForTxId, _BridgeStatusController_getMultichainSelectedAccount, _BridgeStatusController_handleFetchFailure, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_handleNonEvmTx, _BridgeStatusController_waitForHashAndReturnFinalTxMeta, _BridgeStatusController_handleApprovalTx, _BridgeStatusController_handleEvmTransaction, _BridgeStatusController_handleUSDTAllowanceReset, _BridgeStatusController_calculateGasFees, _BridgeStatusController_handleEvmTransactionBatch, _BridgeStatusController_trackUnifiedSwapBridgeEvent;
13
+ var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_addTransactionFn, _BridgeStatusController_addTransactionBatchFn, _BridgeStatusController_updateTransactionFn, _BridgeStatusController_estimateGasFeeFn, _BridgeStatusController_trace, _BridgeStatusController_markTxAsFailed, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_addTxToHistory, _BridgeStatusController_startPollingForTxId, _BridgeStatusController_getMultichainSelectedAccount, _BridgeStatusController_handleFetchFailure, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_fetchIntentOrderStatus, _BridgeStatusController_updateBridgeHistoryFromIntentOrder, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_handleNonEvmTx, _BridgeStatusController_waitForHashAndReturnFinalTxMeta, _BridgeStatusController_waitForTxConfirmation, _BridgeStatusController_handleApprovalTx, _BridgeStatusController_handleEvmTransaction, _BridgeStatusController_handleUSDTAllowanceReset, _BridgeStatusController_calculateGasFees, _BridgeStatusController_handleEvmTransactionBatch, _BridgeStatusController_trackUnifiedSwapBridgeEvent;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.BridgeStatusController = void 0;
16
16
  const bridge_controller_1 = require("@metamask/bridge-controller");
@@ -22,8 +22,10 @@ const constants_1 = require("./constants.cjs");
22
22
  const types_1 = require("./types.cjs");
23
23
  const bridge_status_1 = require("./utils/bridge-status.cjs");
24
24
  const gas_1 = require("./utils/gas.cjs");
25
+ const intent_api_1 = require("./utils/intent-api.cjs");
25
26
  const metrics_1 = require("./utils/metrics.cjs");
26
27
  const transaction_1 = require("./utils/transaction.cjs");
28
+ const validators_1 = require("./utils/validators.cjs");
27
29
  const metadata = {
28
30
  // We want to persist the bridge status state so that we can show the proper data for the Activity list
29
31
  // basically match the behavior of TransactionController
@@ -180,6 +182,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
180
182
  // We know it's in progress but not the exact status yet
181
183
  const txHistoryItem = {
182
184
  txMetaId: bridgeTxMeta.id,
185
+ originalTransactionId: bridgeTxMeta
186
+ .originalTransactionId || bridgeTxMeta.id, // Keep original for intent transactions
183
187
  batchId: bridgeTxMeta.batchId,
184
188
  quote: quoteResponse.quote,
185
189
  startTime,
@@ -225,8 +229,9 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
225
229
  return;
226
230
  }
227
231
  const { quote } = txHistoryItem;
232
+ const isIntent = txId.startsWith('intent:');
228
233
  const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quote.srcChainId, quote.destChainId);
229
- if (isBridgeTx) {
234
+ if (isBridgeTx || isIntent) {
230
235
  __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[txId] = this.startPolling({
231
236
  bridgeTxMetaId: txId,
232
237
  });
@@ -285,6 +290,11 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
285
290
  });
286
291
  _BridgeStatusController_fetchBridgeTxStatus.set(this, async ({ bridgeTxMetaId, }) => {
287
292
  const { txHistory } = this.state;
293
+ // Intent-based items: poll intent provider instead of Bridge API
294
+ if (bridgeTxMetaId.startsWith('intent:')) {
295
+ await __classPrivateFieldGet(this, _BridgeStatusController_fetchIntentOrderStatus, "f").call(this, { bridgeTxMetaId });
296
+ return;
297
+ }
288
298
  if ((0, bridge_status_1.shouldSkipFetchDueToFetchFailures)(txHistory[bridgeTxMetaId]?.attempts)) {
289
299
  return;
290
300
  }
@@ -341,11 +351,38 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
341
351
  }
342
352
  }
343
353
  }
344
- catch (e) {
345
- console.warn('Failed to fetch bridge tx status', e);
354
+ catch (error) {
355
+ console.warn('Failed to fetch bridge tx status', error);
346
356
  __classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
347
357
  }
348
358
  });
359
+ _BridgeStatusController_fetchIntentOrderStatus.set(this, async ({ bridgeTxMetaId, }) => {
360
+ /* c8 ignore start */
361
+ const { txHistory } = this.state;
362
+ const historyItem = txHistory[bridgeTxMetaId];
363
+ if (!historyItem) {
364
+ return;
365
+ }
366
+ // Backoff handling
367
+ if ((0, bridge_status_1.shouldSkipFetchDueToFetchFailures)(historyItem.attempts)) {
368
+ return;
369
+ }
370
+ try {
371
+ const orderId = bridgeTxMetaId.replace(/^intent:/u, '');
372
+ const { srcChainId } = historyItem.quote;
373
+ // Extract provider name from order metadata or default to empty
374
+ const providerName = historyItem.quote.intent?.protocol ?? '';
375
+ const intentApi = new intent_api_1.IntentApiImpl(__classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl, __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
376
+ const intentOrder = await intentApi.getOrderStatus(orderId, providerName, srcChainId.toString(), __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
377
+ // Update bridge history with intent order status
378
+ __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_updateBridgeHistoryFromIntentOrder).call(this, bridgeTxMetaId, intentOrder, historyItem);
379
+ }
380
+ catch (error) {
381
+ console.error('Failed to fetch intent order status:', error);
382
+ __classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
383
+ }
384
+ /* c8 ignore stop */
385
+ });
349
386
  _BridgeStatusController_getSrcTxHash.set(this, (bridgeTxMetaId) => {
350
387
  const { txHistory } = this.state;
351
388
  // Prefer the srcTxHash from bridgeStatusState so we don't have to l ook up in TransactionController
@@ -433,6 +470,35 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
433
470
  }
434
471
  return finalTransactionMeta;
435
472
  });
473
+ // Waits until a given transaction (by id) reaches confirmed/finalized status or fails/times out.
474
+ _BridgeStatusController_waitForTxConfirmation.set(this, async (txId, { timeoutMs = 5 * 60000, // 5 minutes default
475
+ pollMs = 3000, } = {}) => {
476
+ /* c8 ignore start */
477
+ const start = Date.now();
478
+ // Poll the TransactionController state for status changes
479
+ // We intentionally keep this simple to avoid extra wiring/subscriptions in this controller
480
+ // and because we only need it for the rare intent+approval path.
481
+ while (true) {
482
+ const { transactions } = this.messenger.call('TransactionController:getState');
483
+ const meta = transactions.find((tx) => tx.id === txId);
484
+ if (meta) {
485
+ // Treat both 'confirmed' and 'finalized' as success to match TC lifecycle
486
+ if (meta.status === transaction_controller_1.TransactionStatus.confirmed) {
487
+ return meta;
488
+ }
489
+ if (meta.status === transaction_controller_1.TransactionStatus.failed ||
490
+ meta.status === transaction_controller_1.TransactionStatus.dropped ||
491
+ meta.status === transaction_controller_1.TransactionStatus.rejected) {
492
+ throw new Error('Approval transaction did not confirm');
493
+ }
494
+ }
495
+ if (Date.now() - start > timeoutMs) {
496
+ throw new Error('Timed out waiting for approval confirmation');
497
+ }
498
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
499
+ }
500
+ /* c8 ignore stop */
501
+ });
436
502
  _BridgeStatusController_handleApprovalTx.set(this, async (isBridgeTx, srcChainId, approval, resetApproval, requireApproval) => {
437
503
  if (approval) {
438
504
  const approveTx = async () => {
@@ -486,11 +552,17 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
486
552
  type: transactionType,
487
553
  origin: 'metamask',
488
554
  };
555
+ // Exclude gasLimit from trade to avoid type issues (it can be null)
556
+ const { gasLimit: tradeGasLimit, ...tradeWithoutGasLimit } = trade;
489
557
  const transactionParams = {
490
- ...trade,
558
+ ...tradeWithoutGasLimit,
491
559
  chainId: hexChainId,
492
- gasLimit: trade.gasLimit?.toString(),
493
- gas: trade.gasLimit?.toString(),
560
+ // Only add gasLimit and gas if they're valid (not undefined/null/zero)
561
+ ...(tradeGasLimit &&
562
+ tradeGasLimit !== 0 && {
563
+ gasLimit: tradeGasLimit.toString(),
564
+ gas: tradeGasLimit.toString(),
565
+ }),
494
566
  };
495
567
  const transactionParamsWithMaxGas = {
496
568
  ...transactionParams,
@@ -508,14 +580,14 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
508
580
  }
509
581
  });
510
582
  _BridgeStatusController_calculateGasFees.set(this, async (transactionParams, networkClientId, chainId, txFee) => {
511
- const maxGasLimit = (0, controller_utils_1.toHex)(transactionParams.gas ?? 0);
583
+ const { gas } = transactionParams;
512
584
  // If txFee is provided (gasIncluded case), use the quote's gas fees
513
585
  // Convert to hex since txFee values from the quote are decimal strings
514
586
  if (txFee) {
515
587
  return {
516
588
  maxFeePerGas: (0, controller_utils_1.toHex)(txFee.maxFeePerGas ?? 0),
517
589
  maxPriorityFeePerGas: (0, controller_utils_1.toHex)(txFee.maxPriorityFeePerGas ?? 0),
518
- gas: maxGasLimit,
590
+ gas: gas ? (0, controller_utils_1.toHex)(gas) : undefined,
519
591
  };
520
592
  }
521
593
  const { gasFeeEstimates } = this.messenger.call('GasFeeController:getState');
@@ -531,7 +603,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
531
603
  return {
532
604
  maxFeePerGas,
533
605
  maxPriorityFeePerGas,
534
- gas: maxGasLimit,
606
+ gas: gas ? (0, controller_utils_1.toHex)(gas) : undefined,
535
607
  };
536
608
  });
537
609
  /**
@@ -737,6 +809,139 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
737
809
  }
738
810
  return txMeta;
739
811
  };
812
+ /**
813
+ * UI-signed intent submission (fast path): the UI generates the EIP-712 signature and calls this with the raw signature.
814
+ * Here we submit the order to the intent provider and create a synthetic history entry for UX.
815
+ *
816
+ * @param params - Object containing intent submission parameters
817
+ * @param params.quoteResponse - Quote carrying intent data
818
+ * @param params.signature - Hex signature produced by eth_signTypedData_v4
819
+ * @param params.accountAddress - The EOA submitting the order
820
+ * @returns A lightweight TransactionMeta-like object for history linking
821
+ */
822
+ this.submitIntent = async (params) => {
823
+ const { quoteResponse, signature, accountAddress } = params;
824
+ this.messenger.call('BridgeController:stopPollingForQuotes', bridge_controller_1.AbortReason.TransactionSubmitted);
825
+ // Build pre-confirmation properties for error tracking parity with submitTx
826
+ const account = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this, accountAddress);
827
+ const isHardwareAccount = Boolean(account) && (0, bridge_controller_1.isHardwareWallet)(account);
828
+ const preConfirmationProperties = (0, metrics_1.getPreConfirmationPropertiesFromQuote)(quoteResponse, false, isHardwareAccount);
829
+ try {
830
+ const { intent } = quoteResponse
831
+ .quote;
832
+ if (!intent) {
833
+ throw new Error('submitIntent: missing intent data');
834
+ }
835
+ // If backend provided an approval tx for this intent quote, submit it first (on-chain),
836
+ // then proceed with off-chain intent submission.
837
+ let approvalTxId;
838
+ if (quoteResponse.approval) {
839
+ const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
840
+ // Handle approval silently for better UX in intent flows
841
+ const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval && (0, bridge_controller_1.isEvmTxData)(quoteResponse.approval)
842
+ ? quoteResponse.approval
843
+ : undefined, quoteResponse.resetApproval,
844
+ /* requireApproval */ false);
845
+ approvalTxId = approvalTxMeta?.id;
846
+ if (approvalTxId) {
847
+ await __classPrivateFieldGet(this, _BridgeStatusController_waitForTxConfirmation, "f").call(this, approvalTxId);
848
+ }
849
+ }
850
+ const { srcChainId: chainId, requestId } = quoteResponse.quote;
851
+ const submissionParams = {
852
+ srcChainId: chainId.toString(),
853
+ quoteId: requestId,
854
+ signature,
855
+ order: intent.order,
856
+ userAddress: accountAddress,
857
+ aggregatorId: intent.protocol,
858
+ };
859
+ const intentApi = new intent_api_1.IntentApiImpl(__classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl, __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
860
+ const intentOrder = await intentApi.submitIntent(submissionParams, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
861
+ const orderUid = intentOrder.id;
862
+ // Determine transaction type: swap for same-chain, bridge for cross-chain
863
+ const isCrossChainTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
864
+ const transactionType = isCrossChainTx
865
+ ? transaction_controller_1.TransactionType.bridge
866
+ : transaction_controller_1.TransactionType.swap;
867
+ // Create actual transaction in Transaction Controller first
868
+ const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', (0, bridge_controller_1.formatChainIdToHex)(chainId));
869
+ // This is a synthetic transaction whose purpose is to be able
870
+ // to track the order status via the history
871
+ const intentTransactionParams = {
872
+ chainId: (0, bridge_controller_1.formatChainIdToHex)(chainId),
873
+ from: accountAddress,
874
+ to: intent.settlementContract ??
875
+ '0x9008D19f58AAbd9eD0D60971565AA8510560ab41', // Default settlement contract
876
+ data: `0x${orderUid.slice(-8)}`, // Use last 8 chars of orderUid to make each transaction unique
877
+ value: '0x0',
878
+ gas: '0x5208', // Minimal gas for display purposes
879
+ gasPrice: '0x3b9aca00', // 1 Gwei - will be converted to EIP-1559 fees if network supports it
880
+ };
881
+ const { transactionMeta: txMetaPromise } = await __classPrivateFieldGet(this, _BridgeStatusController_addTransactionFn, "f").call(this, intentTransactionParams, {
882
+ origin: 'metamask',
883
+ actionId: (0, transaction_1.generateActionId)(),
884
+ requireApproval: false,
885
+ isStateOnly: true,
886
+ networkClientId,
887
+ type: transactionType,
888
+ });
889
+ const intentTxMeta = txMetaPromise;
890
+ // Map intent order status to TransactionController status
891
+ const initialTransactionStatus = (0, intent_api_1.mapIntentOrderStatusToTransactionStatus)(intentOrder.status);
892
+ // Update transaction with proper initial status based on intent order
893
+ const statusUpdatedTxMeta = {
894
+ ...intentTxMeta,
895
+ status: initialTransactionStatus,
896
+ };
897
+ // Update with actual transaction metadata
898
+ const syntheticMeta = {
899
+ ...statusUpdatedTxMeta,
900
+ isIntentTx: true,
901
+ orderUid,
902
+ intentType: isCrossChainTx ? 'bridge' : 'swap',
903
+ };
904
+ // Record in bridge history with actual transaction metadata
905
+ try {
906
+ // Use 'intent:' prefix for intent transactions
907
+ const bridgeHistoryKey = `intent:${orderUid}`;
908
+ // Create a bridge transaction metadata that includes the original txId
909
+ const bridgeTxMetaForHistory = {
910
+ ...syntheticMeta,
911
+ id: bridgeHistoryKey, // Use intent: prefix for bridge history key
912
+ originalTransactionId: syntheticMeta.id, // Keep original txId for TransactionController updates
913
+ };
914
+ const startTime = Date.now();
915
+ __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
916
+ accountAddress,
917
+ bridgeTxMeta: bridgeTxMetaForHistory,
918
+ statusRequest: {
919
+ ...(0, transaction_1.getStatusRequestParams)(quoteResponse),
920
+ srcTxHash: syntheticMeta.hash ?? '',
921
+ },
922
+ quoteResponse,
923
+ slippagePercentage: 0,
924
+ isStxEnabled: false,
925
+ approvalTxId,
926
+ startTime,
927
+ });
928
+ // Start polling using the intent: prefixed key to route to intent manager
929
+ __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, bridgeHistoryKey);
930
+ }
931
+ catch (error) {
932
+ console.error('📝 [submitIntent] Failed to add to bridge history', error);
933
+ // non-fatal but log the error
934
+ }
935
+ return syntheticMeta;
936
+ }
937
+ catch (error) {
938
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Failed, undefined, {
939
+ error_message: error?.message,
940
+ ...preConfirmationProperties,
941
+ });
942
+ throw error;
943
+ }
944
+ };
740
945
  /**
741
946
  * Tracks post-submission events for a cross-chain swap based on the history item
742
947
  *
@@ -762,13 +967,12 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
762
967
  const requestParamProperties = (0, metrics_1.getRequestParamFromHistory)(historyItem);
763
968
  // Always publish StatusValidationFailed event, regardless of featureId
764
969
  if (eventName === bridge_controller_1.UnifiedSwapBridgeEventName.StatusValidationFailed) {
765
- const { chain_id_source, chain_id_destination, token_address_source, token_address_destination, } = requestParamProperties;
766
970
  this.messenger.call('BridgeController:trackUnifiedSwapBridgeEvent', eventName, {
767
971
  ...baseProperties,
768
- chain_id_source,
769
- chain_id_destination,
770
- token_address_source,
771
- token_address_destination,
972
+ chain_id_source: requestParamProperties.chain_id_source,
973
+ chain_id_destination: requestParamProperties.chain_id_destination,
974
+ token_address_source: requestParamProperties.token_address_source,
975
+ token_address_destination: requestParamProperties.token_address_destination,
772
976
  refresh_count: historyItem.attempts?.counter ?? 0,
773
977
  });
774
978
  return;
@@ -779,8 +983,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
779
983
  }
780
984
  const selectedAccount = this.messenger.call('AccountsController:getAccountByAddress', historyItem.account);
781
985
  const { transactions } = this.messenger.call('TransactionController:getState');
782
- const txMeta = transactions?.find(({ id }) => id === txMetaId);
783
- const approvalTxMeta = transactions?.find(({ id }) => id === historyItem.approvalTxId);
986
+ const txMeta = transactions?.find((tx) => tx.id === txMetaId);
987
+ const approvalTxMeta = transactions?.find((tx) => tx.id === historyItem.approvalTxId);
784
988
  const requiredEventProperties = {
785
989
  ...baseProperties,
786
990
  ...requestParamProperties,
@@ -807,6 +1011,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
807
1011
  this.messenger.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
808
1012
  this.messenger.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
809
1013
  this.messenger.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this));
1014
+ this.messenger.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:submitIntent`, this.submitIntent.bind(this));
810
1015
  this.messenger.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:restartPollingForFailedAttempts`, this.restartPollingForFailedAttempts.bind(this));
811
1016
  this.messenger.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:getBridgeHistoryItemByTxMetaId`, this.getBridgeHistoryItemByTxMetaId.bind(this));
812
1017
  // Set interval
@@ -849,7 +1054,128 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
849
1054
  }
850
1055
  }
851
1056
  exports.BridgeStatusController = BridgeStatusController;
852
- _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_addTransactionFn = new WeakMap(), _BridgeStatusController_addTransactionBatchFn = new WeakMap(), _BridgeStatusController_updateTransactionFn = new WeakMap(), _BridgeStatusController_estimateGasFeeFn = new WeakMap(), _BridgeStatusController_trace = new WeakMap(), _BridgeStatusController_markTxAsFailed = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_addTxToHistory = new WeakMap(), _BridgeStatusController_startPollingForTxId = new WeakMap(), _BridgeStatusController_handleFetchFailure = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_handleNonEvmTx = new WeakMap(), _BridgeStatusController_waitForHashAndReturnFinalTxMeta = new WeakMap(), _BridgeStatusController_handleApprovalTx = new WeakMap(), _BridgeStatusController_handleEvmTransaction = new WeakMap(), _BridgeStatusController_handleUSDTAllowanceReset = new WeakMap(), _BridgeStatusController_calculateGasFees = new WeakMap(), _BridgeStatusController_handleEvmTransactionBatch = new WeakMap(), _BridgeStatusController_trackUnifiedSwapBridgeEvent = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getMultichainSelectedAccount = function _BridgeStatusController_getMultichainSelectedAccount(accountAddress) {
1057
+ _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_addTransactionFn = new WeakMap(), _BridgeStatusController_addTransactionBatchFn = new WeakMap(), _BridgeStatusController_updateTransactionFn = new WeakMap(), _BridgeStatusController_estimateGasFeeFn = new WeakMap(), _BridgeStatusController_trace = new WeakMap(), _BridgeStatusController_markTxAsFailed = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_addTxToHistory = new WeakMap(), _BridgeStatusController_startPollingForTxId = new WeakMap(), _BridgeStatusController_handleFetchFailure = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_fetchIntentOrderStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_handleNonEvmTx = new WeakMap(), _BridgeStatusController_waitForHashAndReturnFinalTxMeta = new WeakMap(), _BridgeStatusController_waitForTxConfirmation = new WeakMap(), _BridgeStatusController_handleApprovalTx = new WeakMap(), _BridgeStatusController_handleEvmTransaction = new WeakMap(), _BridgeStatusController_handleUSDTAllowanceReset = new WeakMap(), _BridgeStatusController_calculateGasFees = new WeakMap(), _BridgeStatusController_handleEvmTransactionBatch = new WeakMap(), _BridgeStatusController_trackUnifiedSwapBridgeEvent = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getMultichainSelectedAccount = function _BridgeStatusController_getMultichainSelectedAccount(accountAddress) {
853
1058
  return this.messenger.call('AccountsController:getAccountByAddress', accountAddress);
1059
+ }, _BridgeStatusController_updateBridgeHistoryFromIntentOrder = function _BridgeStatusController_updateBridgeHistoryFromIntentOrder(bridgeTxMetaId, intentOrder, historyItem) {
1060
+ const { srcChainId } = historyItem.quote;
1061
+ // Map intent order status to bridge status using enum values
1062
+ let statusType;
1063
+ const isComplete = [
1064
+ validators_1.IntentOrderStatus.CONFIRMED,
1065
+ validators_1.IntentOrderStatus.COMPLETED,
1066
+ ].includes(intentOrder.status);
1067
+ const isFailed = [
1068
+ validators_1.IntentOrderStatus.FAILED,
1069
+ validators_1.IntentOrderStatus.EXPIRED,
1070
+ validators_1.IntentOrderStatus.CANCELLED,
1071
+ ].includes(intentOrder.status);
1072
+ const isPending = [validators_1.IntentOrderStatus.PENDING].includes(intentOrder.status);
1073
+ const isSubmitted = [validators_1.IntentOrderStatus.SUBMITTED].includes(intentOrder.status);
1074
+ if (isComplete) {
1075
+ statusType = bridge_controller_1.StatusTypes.COMPLETE;
1076
+ }
1077
+ else if (isFailed) {
1078
+ statusType = bridge_controller_1.StatusTypes.FAILED;
1079
+ }
1080
+ else if (isPending) {
1081
+ statusType = bridge_controller_1.StatusTypes.PENDING;
1082
+ }
1083
+ else if (isSubmitted) {
1084
+ statusType = bridge_controller_1.StatusTypes.SUBMITTED;
1085
+ }
1086
+ else {
1087
+ statusType = bridge_controller_1.StatusTypes.UNKNOWN;
1088
+ }
1089
+ // Extract transaction hashes from intent order
1090
+ const txHash = intentOrder.txHash ?? '';
1091
+ // Check metadata for additional transaction hashes
1092
+ const metadataTxHashes = Array.isArray(intentOrder.metadata.txHashes)
1093
+ ? intentOrder.metadata.txHashes
1094
+ : [];
1095
+ let allHashes;
1096
+ if (metadataTxHashes.length > 0) {
1097
+ allHashes = metadataTxHashes;
1098
+ }
1099
+ else if (txHash) {
1100
+ allHashes = [txHash];
1101
+ }
1102
+ else {
1103
+ allHashes = [];
1104
+ }
1105
+ const newStatus = {
1106
+ status: statusType,
1107
+ srcChain: {
1108
+ chainId: srcChainId,
1109
+ txHash: txHash ?? historyItem.status.srcChain.txHash ?? '',
1110
+ },
1111
+ };
1112
+ const newBridgeHistoryItem = {
1113
+ ...historyItem,
1114
+ status: newStatus,
1115
+ completionTime: newStatus.status === bridge_controller_1.StatusTypes.COMPLETE ||
1116
+ newStatus.status === bridge_controller_1.StatusTypes.FAILED
1117
+ ? Date.now()
1118
+ : undefined,
1119
+ attempts: undefined,
1120
+ srcTxHashes: allHashes.length > 0
1121
+ ? Array.from(new Set([...(historyItem.srcTxHashes ?? []), ...allHashes]))
1122
+ : historyItem.srcTxHashes,
1123
+ };
1124
+ this.update((state) => {
1125
+ state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;
1126
+ });
1127
+ // Update the actual transaction in TransactionController to sync with intent status
1128
+ // Use the original transaction ID (not the intent: prefixed bridge history key)
1129
+ const originalTxId = historyItem.originalTransactionId ?? historyItem.txMetaId;
1130
+ if (originalTxId && !originalTxId.startsWith('intent:')) {
1131
+ try {
1132
+ const transactionStatus = (0, intent_api_1.mapIntentOrderStatusToTransactionStatus)(intentOrder.status);
1133
+ // Merge with existing TransactionMeta to avoid wiping required fields
1134
+ const { transactions } = this.messenger.call('TransactionController:getState');
1135
+ const existingTxMeta = transactions.find((tx) => tx.id === originalTxId);
1136
+ if (existingTxMeta) {
1137
+ const updatedTxMeta = {
1138
+ ...existingTxMeta,
1139
+ status: transactionStatus,
1140
+ ...(txHash ? { hash: txHash } : {}),
1141
+ ...(txHash
1142
+ ? {
1143
+ txReceipt: {
1144
+ ...existingTxMeta.txReceipt,
1145
+ transactionHash: txHash,
1146
+ status: (isComplete ? '0x1' : '0x0'),
1147
+ },
1148
+ }
1149
+ : {}),
1150
+ };
1151
+ __classPrivateFieldGet(this, _BridgeStatusController_updateTransactionFn, "f").call(this, updatedTxMeta, `BridgeStatusController - Intent order status updated: ${intentOrder.status}`);
1152
+ }
1153
+ else {
1154
+ console.warn('📝 [fetchIntentOrderStatus] Skipping update; transaction not found', { originalTxId, bridgeHistoryKey: bridgeTxMetaId });
1155
+ }
1156
+ }
1157
+ catch (error) {
1158
+ /* c8 ignore start */
1159
+ console.error('📝 [fetchIntentOrderStatus] Failed to update transaction status', {
1160
+ originalTxId,
1161
+ bridgeHistoryKey: bridgeTxMetaId,
1162
+ error,
1163
+ });
1164
+ }
1165
+ /* c8 ignore stop */
1166
+ }
1167
+ const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
1168
+ const isFinal = newStatus.status === bridge_controller_1.StatusTypes.COMPLETE ||
1169
+ newStatus.status === bridge_controller_1.StatusTypes.FAILED;
1170
+ if (isFinal && pollingToken) {
1171
+ this.stopPollingByPollingToken(pollingToken);
1172
+ delete __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
1173
+ if (newStatus.status === bridge_controller_1.StatusTypes.COMPLETE) {
1174
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Completed, bridgeTxMetaId);
1175
+ }
1176
+ else if (newStatus.status === bridge_controller_1.StatusTypes.FAILED) {
1177
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Failed, bridgeTxMetaId);
1178
+ }
1179
+ }
854
1180
  };
855
1181
  //# sourceMappingURL=bridge-status-controller.cjs.map