@metamask-previews/bridge-status-controller 64.2.0-preview-d24ded2 → 64.2.0-preview-749d0638

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 (38) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/bridge-status-controller.cjs +403 -15
  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 +403 -15
  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/intent-api.cjs +73 -0
  19. package/dist/utils/intent-api.cjs.map +1 -0
  20. package/dist/utils/intent-api.d.cts +24 -0
  21. package/dist/utils/intent-api.d.cts.map +1 -0
  22. package/dist/utils/intent-api.d.mts +24 -0
  23. package/dist/utils/intent-api.d.mts.map +1 -0
  24. package/dist/utils/intent-api.mjs +68 -0
  25. package/dist/utils/intent-api.mjs.map +1 -0
  26. package/dist/utils/transaction.d.cts +21 -2
  27. package/dist/utils/transaction.d.cts.map +1 -1
  28. package/dist/utils/transaction.d.mts +21 -2
  29. package/dist/utils/transaction.d.mts.map +1 -1
  30. package/dist/utils/validators.cjs +23 -1
  31. package/dist/utils/validators.cjs.map +1 -1
  32. package/dist/utils/validators.d.cts +51 -0
  33. package/dist/utils/validators.d.cts.map +1 -1
  34. package/dist/utils/validators.d.mts +51 -0
  35. package/dist/utils/validators.d.mts.map +1 -1
  36. package/dist/utils/validators.mjs +22 -1
  37. package/dist/utils/validators.mjs.map +1 -1
  38. package/package.json +3 -3
@@ -9,18 +9,20 @@ 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_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;
12
+ 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_convertBridgeQuoteToIntentQuote, _BridgeStatusController_mapIntentOrderStatusToTransactionStatus, _BridgeStatusController_trackUnifiedSwapBridgeEvent;
13
13
  import { formatChainIdToHex, isNonEvmChainId, StatusTypes, UnifiedSwapBridgeEventName, formatChainIdToCaip, isCrossChain, isEvmTxData, isHardwareWallet, MetricsActionType, isBitcoinTrade, isTronTrade, AbortReason } from "@metamask/bridge-controller";
14
14
  import { toHex } from "@metamask/controller-utils";
15
15
  import { StaticIntervalPollingController } from "@metamask/polling-controller";
16
16
  import { TransactionStatus, TransactionType } from "@metamask/transaction-controller";
17
17
  import { numberToHex } from "@metamask/utils";
18
18
  import { BRIDGE_PROD_API_BASE_URL, BRIDGE_STATUS_CONTROLLER_NAME, DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE, MAX_ATTEMPTS, REFRESH_INTERVAL_MS, TraceName } from "./constants.mjs";
19
+ import { IntentApiImpl } from "./utils/intent-api.mjs";
19
20
  import { BridgeClientId } from "./types.mjs";
20
21
  import { fetchBridgeTxStatus, getStatusRequestWithSrcTxHash, shouldSkipFetchDueToFetchFailures } from "./utils/bridge-status.mjs";
21
22
  import { getTxGasEstimates } from "./utils/gas.mjs";
22
23
  import { getFinalizedTxProperties, getPriceImpactFromQuote, getRequestMetadataFromHistory, getRequestParamFromHistory, getTradeDataFromHistory, getEVMTxPropertiesFromTransactionMeta, getTxStatusesFromHistory, getPreConfirmationPropertiesFromQuote } from "./utils/metrics.mjs";
23
24
  import { findAndUpdateTransactionsInBatch, getAddTransactionBatchParams, getClientRequest, getStatusRequestParams, handleApprovalDelay, handleMobileHardwareWalletDelay, handleNonEvmTxResponse, generateActionId } from "./utils/transaction.mjs";
25
+ import { IntentOrderStatus } from "./utils/validators.mjs";
24
26
  const metadata = {
25
27
  // We want to persist the bridge status state so that we can show the proper data for the Activity list
26
28
  // basically match the behavior of TransactionController
@@ -177,6 +179,8 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
177
179
  // We know it's in progress but not the exact status yet
178
180
  const txHistoryItem = {
179
181
  txMetaId: bridgeTxMeta.id,
182
+ originalTransactionId: bridgeTxMeta
183
+ .originalTransactionId || bridgeTxMeta.id, // Keep original for intent transactions
180
184
  batchId: bridgeTxMeta.batchId,
181
185
  quote: quoteResponse.quote,
182
186
  startTime,
@@ -222,8 +226,9 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
222
226
  return;
223
227
  }
224
228
  const { quote } = txHistoryItem;
229
+ const isIntent = txId.startsWith('intent:');
225
230
  const isBridgeTx = isCrossChain(quote.srcChainId, quote.destChainId);
226
- if (isBridgeTx) {
231
+ if (isBridgeTx || isIntent) {
227
232
  __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[txId] = this.startPolling({
228
233
  bridgeTxMetaId: txId,
229
234
  });
@@ -282,6 +287,11 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
282
287
  });
283
288
  _BridgeStatusController_fetchBridgeTxStatus.set(this, async ({ bridgeTxMetaId, }) => {
284
289
  const { txHistory } = this.state;
290
+ // Intent-based items: poll intent provider instead of Bridge API
291
+ if (bridgeTxMetaId.startsWith('intent:')) {
292
+ await __classPrivateFieldGet(this, _BridgeStatusController_fetchIntentOrderStatus, "f").call(this, { bridgeTxMetaId });
293
+ return;
294
+ }
285
295
  if (shouldSkipFetchDueToFetchFailures(txHistory[bridgeTxMetaId]?.attempts)) {
286
296
  return;
287
297
  }
@@ -338,8 +348,33 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
338
348
  }
339
349
  }
340
350
  }
341
- catch (e) {
342
- console.warn('Failed to fetch bridge tx status', e);
351
+ catch (error) {
352
+ console.warn('Failed to fetch bridge tx status', error);
353
+ __classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
354
+ }
355
+ });
356
+ _BridgeStatusController_fetchIntentOrderStatus.set(this, async ({ bridgeTxMetaId, }) => {
357
+ const { txHistory } = this.state;
358
+ const historyItem = txHistory[bridgeTxMetaId];
359
+ if (!historyItem) {
360
+ return;
361
+ }
362
+ // Backoff handling
363
+ if (shouldSkipFetchDueToFetchFailures(historyItem.attempts)) {
364
+ return;
365
+ }
366
+ try {
367
+ const orderId = bridgeTxMetaId.replace(/^intent:/u, '');
368
+ const { srcChainId } = historyItem.quote;
369
+ // Extract provider name from order metadata or default to empty
370
+ const providerName = historyItem.quote.intent?.protocol ?? '';
371
+ const intentApi = new IntentApiImpl(__classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl, __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
372
+ const intentOrder = await intentApi.getOrderStatus(orderId, providerName, srcChainId.toString(), __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
373
+ // Update bridge history with intent order status
374
+ __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_updateBridgeHistoryFromIntentOrder).call(this, bridgeTxMetaId, intentOrder, historyItem);
375
+ }
376
+ catch (error) {
377
+ console.error('Failed to fetch intent order status:', error);
343
378
  __classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
344
379
  }
345
380
  });
@@ -430,6 +465,36 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
430
465
  }
431
466
  return finalTransactionMeta;
432
467
  });
468
+ // Waits until a given transaction (by id) reaches confirmed/finalized status or fails/times out.
469
+ _BridgeStatusController_waitForTxConfirmation.set(this, async (txId, { timeoutMs = 5 * 60000, // 5 minutes default
470
+ pollMs = 2000, } = {}) => {
471
+ const start = Date.now();
472
+ // Poll the TransactionController state for status changes
473
+ // We intentionally keep this simple to avoid extra wiring/subscriptions in this controller
474
+ // and because we only need it for the rare intent+approval path.
475
+ while (true) {
476
+ const { transactions } = this.messenger.call('TransactionController:getState');
477
+ const meta = transactions.find((tx) => tx.id === txId);
478
+ if (meta) {
479
+ // Treat both 'confirmed' and 'finalized' as success to match TC lifecycle
480
+ if (meta.status === TransactionStatus.confirmed ||
481
+ // Some environments move directly to finalized
482
+ TransactionStatus.finalized ===
483
+ meta.status) {
484
+ return meta;
485
+ }
486
+ if (meta.status === TransactionStatus.failed ||
487
+ meta.status === TransactionStatus.dropped ||
488
+ meta.status === TransactionStatus.rejected) {
489
+ throw new Error('Approval transaction did not confirm');
490
+ }
491
+ }
492
+ if (Date.now() - start > timeoutMs) {
493
+ throw new Error('Timed out waiting for approval confirmation');
494
+ }
495
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
496
+ }
497
+ });
433
498
  _BridgeStatusController_handleApprovalTx.set(this, async (isBridgeTx, srcChainId, approval, resetApproval, requireApproval) => {
434
499
  if (approval) {
435
500
  const approveTx = async () => {
@@ -483,11 +548,17 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
483
548
  type: transactionType,
484
549
  origin: 'metamask',
485
550
  };
551
+ // Exclude gasLimit from trade to avoid type issues (it can be null)
552
+ const { gasLimit: tradeGasLimit, ...tradeWithoutGasLimit } = trade;
486
553
  const transactionParams = {
487
- ...trade,
554
+ ...tradeWithoutGasLimit,
488
555
  chainId: hexChainId,
489
- gasLimit: trade.gasLimit?.toString(),
490
- gas: trade.gasLimit?.toString(),
556
+ // Only add gasLimit and gas if they're valid (not undefined/null/zero)
557
+ ...(tradeGasLimit &&
558
+ tradeGasLimit !== 0 && {
559
+ gasLimit: tradeGasLimit.toString(),
560
+ gas: tradeGasLimit.toString(),
561
+ }),
491
562
  };
492
563
  const transactionParamsWithMaxGas = {
493
564
  ...transactionParams,
@@ -734,6 +805,168 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
734
805
  }
735
806
  return txMeta;
736
807
  };
808
+ /**
809
+ * UI-signed intent submission (fast path): the UI generates the EIP-712 signature and calls this with the raw signature.
810
+ * Here we submit the order to the intent provider and create a synthetic history entry for UX.
811
+ *
812
+ * @param params - Object containing intent submission parameters
813
+ * @param params.quoteResponse - Quote carrying intent data
814
+ * @param params.signature - Hex signature produced by eth_signTypedData_v4
815
+ * @param params.accountAddress - The EOA submitting the order
816
+ * @returns A lightweight TransactionMeta-like object for history linking
817
+ */
818
+ this.submitIntent = async (params) => {
819
+ const { quoteResponse, signature, accountAddress } = params;
820
+ // Build pre-confirmation properties for error tracking parity with submitTx
821
+ const account = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this, accountAddress);
822
+ const isHardwareAccount = Boolean(account) && isHardwareWallet(account);
823
+ const preConfirmationProperties = getPreConfirmationPropertiesFromQuote(quoteResponse, false, isHardwareAccount);
824
+ try {
825
+ const { intent } = quoteResponse
826
+ .quote;
827
+ if (!intent) {
828
+ throw new Error('submitIntent: missing intent data');
829
+ }
830
+ // If backend provided an approval tx for this intent quote, submit it first (on-chain),
831
+ // then proceed with off-chain intent submission.
832
+ let approvalTxId;
833
+ if (quoteResponse.approval) {
834
+ const isBridgeTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
835
+ // Handle approval silently for better UX in intent flows
836
+ const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval && isEvmTxData(quoteResponse.approval)
837
+ ? quoteResponse.approval
838
+ : undefined, quoteResponse.resetApproval,
839
+ /* requireApproval */ false);
840
+ approvalTxId = approvalTxMeta?.id;
841
+ // Optionally wait for approval confirmation with timeout and graceful fallback
842
+ // Intent order can be created before allowance is mined, but waiting helps avoid MEV issues
843
+ if (approvalTxId) {
844
+ try {
845
+ // Wait with a shorter timeout and continue if it fails
846
+ await __classPrivateFieldGet(this, _BridgeStatusController_waitForTxConfirmation, "f").call(this, approvalTxId, {
847
+ timeoutMs: 30000, // 30 seconds instead of 5 minutes
848
+ pollMs: 3000, // Poll less frequently to avoid rate limits
849
+ });
850
+ }
851
+ catch (error) {
852
+ // Log but don't throw - continue with intent order submission
853
+ console.warn('Approval confirmation failed, continuing with intent submission:', error);
854
+ }
855
+ }
856
+ }
857
+ // Create intent quote from bridge quote response
858
+ const intentQuote = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_convertBridgeQuoteToIntentQuote).call(this, quoteResponse, intent);
859
+ const chainId = quoteResponse.quote.srcChainId;
860
+ const submissionParams = {
861
+ srcChainId: chainId.toString(),
862
+ quoteId: intentQuote.id,
863
+ signature,
864
+ order: intentQuote.metadata.order,
865
+ userAddress: accountAddress,
866
+ aggregatorId: 'cowswap',
867
+ };
868
+ const intentApi = new IntentApiImpl(__classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl, __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
869
+ const intentOrder = (await intentApi.submitIntent(submissionParams, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f")));
870
+ const orderUid = intentOrder.id;
871
+ // Determine transaction type: swap for same-chain, bridge for cross-chain
872
+ const isCrossChainTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
873
+ const transactionType = isCrossChainTx
874
+ ? TransactionType.bridge
875
+ : TransactionType.swap;
876
+ // Create actual transaction in Transaction Controller first
877
+ const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', formatChainIdToHex(chainId));
878
+ const intentTransactionParams = {
879
+ chainId: formatChainIdToHex(chainId),
880
+ from: accountAddress,
881
+ to: intent.settlementContract ??
882
+ '0x9008D19f58AAbd9eD0D60971565AA8510560ab41', // Default settlement contract
883
+ data: `0x${orderUid.slice(-8)}`, // Use last 8 chars of orderUid to make each transaction unique
884
+ value: '0x0',
885
+ gas: '0x5208', // Minimal gas for display purposes
886
+ gasPrice: '0x3b9aca00', // 1 Gwei - will be converted to EIP-1559 fees if network supports it
887
+ };
888
+ const { transactionMeta: txMetaPromise } = await __classPrivateFieldGet(this, _BridgeStatusController_addTransactionFn, "f").call(this, intentTransactionParams, {
889
+ origin: 'metamask',
890
+ actionId: generateActionId(),
891
+ requireApproval: false,
892
+ networkClientId,
893
+ type: transactionType,
894
+ skipInitialGasEstimate: true,
895
+ swaps: {
896
+ meta: {
897
+ // Add token symbols from quoteResponse for proper display
898
+ sourceTokenSymbol: quoteResponse.quote.srcAsset.symbol,
899
+ destinationTokenSymbol: quoteResponse.quote.destAsset.symbol,
900
+ sourceTokenAmount: quoteResponse.quote.srcTokenAmount,
901
+ destinationTokenAmount: quoteResponse.quote.destTokenAmount,
902
+ sourceTokenDecimals: quoteResponse.quote.srcAsset.decimals,
903
+ destinationTokenDecimals: quoteResponse.quote.destAsset.decimals,
904
+ sourceTokenAddress: quoteResponse.quote.srcAsset.address,
905
+ destinationTokenAddress: quoteResponse.quote.destAsset.address,
906
+ swapTokenValue: quoteResponse.sentAmount.amount,
907
+ approvalTxId,
908
+ swapMetaData: {
909
+ isIntentTx: true,
910
+ orderUid,
911
+ intentType: isCrossChainTx ? 'bridge' : 'swap',
912
+ },
913
+ },
914
+ },
915
+ });
916
+ const intentTxMeta = txMetaPromise;
917
+ // Map intent order status to TransactionController status
918
+ const initialTransactionStatus = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_mapIntentOrderStatusToTransactionStatus).call(this, intentOrder.status);
919
+ // Update transaction with proper initial status based on intent order
920
+ const statusUpdatedTxMeta = {
921
+ ...intentTxMeta,
922
+ status: initialTransactionStatus,
923
+ };
924
+ // Update with actual transaction metadata
925
+ const syntheticMeta = {
926
+ ...statusUpdatedTxMeta,
927
+ isIntentTx: true,
928
+ orderUid,
929
+ intentType: isCrossChainTx ? 'bridge' : 'swap',
930
+ };
931
+ // Record in bridge history with actual transaction metadata
932
+ try {
933
+ // Use 'intent:' prefix for intent transactions
934
+ const bridgeHistoryKey = `intent:${orderUid}`;
935
+ // Create a bridge transaction metadata that includes the original txId
936
+ const bridgeTxMetaForHistory = {
937
+ ...syntheticMeta,
938
+ id: bridgeHistoryKey, // Use intent: prefix for bridge history key
939
+ originalTransactionId: syntheticMeta.id, // Keep original txId for TransactionController updates
940
+ };
941
+ __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
942
+ accountAddress,
943
+ bridgeTxMeta: bridgeTxMetaForHistory,
944
+ statusRequest: {
945
+ ...getStatusRequestParams(quoteResponse),
946
+ srcTxHash: syntheticMeta.hash ?? '',
947
+ },
948
+ quoteResponse,
949
+ slippagePercentage: 0,
950
+ isStxEnabled: false,
951
+ approvalTxId,
952
+ });
953
+ // Start polling using the intent: prefixed key to route to intent manager
954
+ __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, bridgeHistoryKey);
955
+ }
956
+ catch (error) {
957
+ console.error('📝 [submitIntent] Failed to add to bridge history', error);
958
+ // non-fatal but log the error
959
+ }
960
+ return syntheticMeta;
961
+ }
962
+ catch (error) {
963
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, undefined, {
964
+ error_message: error?.message,
965
+ ...preConfirmationProperties,
966
+ });
967
+ throw error;
968
+ }
969
+ };
737
970
  /**
738
971
  * Tracks post-submission events for a cross-chain swap based on the history item
739
972
  *
@@ -759,13 +992,12 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
759
992
  const requestParamProperties = getRequestParamFromHistory(historyItem);
760
993
  // Always publish StatusValidationFailed event, regardless of featureId
761
994
  if (eventName === UnifiedSwapBridgeEventName.StatusValidationFailed) {
762
- const { chain_id_source, chain_id_destination, token_address_source, token_address_destination, } = requestParamProperties;
763
995
  this.messenger.call('BridgeController:trackUnifiedSwapBridgeEvent', eventName, {
764
996
  ...baseProperties,
765
- chain_id_source,
766
- chain_id_destination,
767
- token_address_source,
768
- token_address_destination,
997
+ chain_id_source: requestParamProperties.chain_id_source,
998
+ chain_id_destination: requestParamProperties.chain_id_destination,
999
+ token_address_source: requestParamProperties.token_address_source,
1000
+ token_address_destination: requestParamProperties.token_address_destination,
769
1001
  refresh_count: historyItem.attempts?.counter ?? 0,
770
1002
  });
771
1003
  return;
@@ -776,8 +1008,8 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
776
1008
  }
777
1009
  const selectedAccount = this.messenger.call('AccountsController:getAccountByAddress', historyItem.account);
778
1010
  const { transactions } = this.messenger.call('TransactionController:getState');
779
- const txMeta = transactions?.find(({ id }) => id === txMetaId);
780
- const approvalTxMeta = transactions?.find(({ id }) => id === historyItem.approvalTxId);
1011
+ const txMeta = transactions?.find((tx) => tx.id === txMetaId);
1012
+ const approvalTxMeta = transactions?.find((tx) => tx.id === historyItem.approvalTxId);
781
1013
  const requiredEventProperties = {
782
1014
  ...baseProperties,
783
1015
  ...requestParamProperties,
@@ -804,12 +1036,18 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
804
1036
  this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
805
1037
  this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
806
1038
  this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this));
1039
+ this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:submitIntent`, this.submitIntent.bind(this));
807
1040
  this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:restartPollingForFailedAttempts`, this.restartPollingForFailedAttempts.bind(this));
808
1041
  this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:getBridgeHistoryItemByTxMetaId`, this.getBridgeHistoryItemByTxMetaId.bind(this));
809
1042
  // Set interval
810
1043
  this.setIntervalLength(REFRESH_INTERVAL_MS);
811
1044
  this.messenger.subscribe('TransactionController:transactionFailed', ({ transactionMeta }) => {
812
1045
  const { type, status, id } = transactionMeta;
1046
+ // Skip intent transactions - they have their own tracking via CoW API
1047
+ if (transactionMeta
1048
+ .swapMetaData?.isIntentTx) {
1049
+ return;
1050
+ }
813
1051
  if (type &&
814
1052
  [
815
1053
  TransactionType.bridge,
@@ -845,7 +1083,157 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
845
1083
  __classPrivateFieldGet(this, _BridgeStatusController_restartPollingForIncompleteHistoryItems, "f").call(this);
846
1084
  }
847
1085
  }
848
- _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) {
1086
+ _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) {
849
1087
  return this.messenger.call('AccountsController:getAccountByAddress', accountAddress);
1088
+ }, _BridgeStatusController_updateBridgeHistoryFromIntentOrder = function _BridgeStatusController_updateBridgeHistoryFromIntentOrder(bridgeTxMetaId, intentOrder, historyItem) {
1089
+ const { srcChainId } = historyItem.quote;
1090
+ // Map intent order status to bridge status using enum values
1091
+ let statusType;
1092
+ const isComplete = [
1093
+ IntentOrderStatus.CONFIRMED,
1094
+ IntentOrderStatus.COMPLETED,
1095
+ ].includes(intentOrder.status);
1096
+ const isFailed = [
1097
+ IntentOrderStatus.FAILED,
1098
+ IntentOrderStatus.EXPIRED,
1099
+ ].includes(intentOrder.status);
1100
+ const isPending = [IntentOrderStatus.PENDING].includes(intentOrder.status);
1101
+ const isSubmitted = [IntentOrderStatus.SUBMITTED].includes(intentOrder.status);
1102
+ if (isComplete) {
1103
+ statusType = StatusTypes.COMPLETE;
1104
+ }
1105
+ else if (isFailed) {
1106
+ statusType = StatusTypes.FAILED;
1107
+ }
1108
+ else if (isPending) {
1109
+ statusType = StatusTypes.PENDING;
1110
+ }
1111
+ else if (isSubmitted) {
1112
+ statusType = StatusTypes.SUBMITTED;
1113
+ }
1114
+ else {
1115
+ statusType = StatusTypes.UNKNOWN;
1116
+ }
1117
+ // Extract transaction hashes from intent order
1118
+ const txHash = intentOrder.txHash ?? '';
1119
+ // Check metadata for additional transaction hashes
1120
+ const metadataTxHashes = Array.isArray(intentOrder.metadata.txHashes)
1121
+ ? intentOrder.metadata.txHashes
1122
+ : [];
1123
+ let allHashes;
1124
+ if (metadataTxHashes.length > 0) {
1125
+ allHashes = metadataTxHashes;
1126
+ }
1127
+ else if (txHash) {
1128
+ allHashes = [txHash];
1129
+ }
1130
+ else {
1131
+ allHashes = [];
1132
+ }
1133
+ const newStatus = {
1134
+ status: statusType,
1135
+ srcChain: {
1136
+ chainId: srcChainId,
1137
+ txHash: txHash ?? historyItem.status.srcChain.txHash ?? '',
1138
+ },
1139
+ };
1140
+ const newBridgeHistoryItem = {
1141
+ ...historyItem,
1142
+ status: newStatus,
1143
+ completionTime: newStatus.status === StatusTypes.COMPLETE ||
1144
+ newStatus.status === StatusTypes.FAILED
1145
+ ? Date.now()
1146
+ : undefined,
1147
+ attempts: undefined,
1148
+ srcTxHashes: allHashes.length > 0
1149
+ ? Array.from(new Set([...(historyItem.srcTxHashes ?? []), ...allHashes]))
1150
+ : historyItem.srcTxHashes,
1151
+ };
1152
+ this.update((state) => {
1153
+ state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;
1154
+ });
1155
+ // Update the actual transaction in TransactionController to sync with intent status
1156
+ // Use the original transaction ID (not the intent: prefixed bridge history key)
1157
+ const originalTxId = historyItem.originalTransactionId ?? historyItem.txMetaId;
1158
+ if (originalTxId && !originalTxId.startsWith('intent:')) {
1159
+ try {
1160
+ const transactionStatus = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_mapIntentOrderStatusToTransactionStatus).call(this, intentOrder.status);
1161
+ // Merge with existing TransactionMeta to avoid wiping required fields
1162
+ const { transactions } = this.messenger.call('TransactionController:getState');
1163
+ const existingTxMeta = transactions.find((tx) => tx.id === originalTxId);
1164
+ if (existingTxMeta) {
1165
+ const updatedTxMeta = {
1166
+ ...existingTxMeta,
1167
+ status: transactionStatus,
1168
+ ...(txHash ? { hash: txHash } : {}),
1169
+ ...(txHash
1170
+ ? {
1171
+ txReceipt: {
1172
+ ...existingTxMeta.txReceipt,
1173
+ transactionHash: txHash,
1174
+ status: (isComplete ? '0x1' : '0x0'),
1175
+ },
1176
+ }
1177
+ : {}),
1178
+ };
1179
+ __classPrivateFieldGet(this, _BridgeStatusController_updateTransactionFn, "f").call(this, updatedTxMeta, `BridgeStatusController - Intent order status updated: ${intentOrder.status}`);
1180
+ }
1181
+ else {
1182
+ console.warn('📝 [fetchIntentOrderStatus] Skipping update; transaction not found', { originalTxId, bridgeHistoryKey: bridgeTxMetaId });
1183
+ }
1184
+ }
1185
+ catch (error) {
1186
+ console.error('📝 [fetchIntentOrderStatus] Failed to update transaction status', {
1187
+ originalTxId,
1188
+ bridgeHistoryKey: bridgeTxMetaId,
1189
+ error,
1190
+ });
1191
+ }
1192
+ }
1193
+ const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
1194
+ const isFinal = newStatus.status === StatusTypes.COMPLETE ||
1195
+ newStatus.status === StatusTypes.FAILED;
1196
+ if (isFinal && pollingToken) {
1197
+ this.stopPollingByPollingToken(pollingToken);
1198
+ delete __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
1199
+ if (newStatus.status === StatusTypes.COMPLETE) {
1200
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Completed, bridgeTxMetaId);
1201
+ }
1202
+ else if (newStatus.status === StatusTypes.FAILED) {
1203
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, bridgeTxMetaId);
1204
+ }
1205
+ }
1206
+ }, _BridgeStatusController_convertBridgeQuoteToIntentQuote = function _BridgeStatusController_convertBridgeQuoteToIntentQuote(quoteResponse, intent) {
1207
+ return {
1208
+ id: `bridge-${Date.now()}`,
1209
+ provider: intent.protocol,
1210
+ srcAmount: quoteResponse.quote.srcTokenAmount,
1211
+ destAmount: quoteResponse.quote.destTokenAmount,
1212
+ estimatedGas: '21000',
1213
+ estimatedTime: 300, // 5 minutes
1214
+ priceImpact: 0,
1215
+ fees: [],
1216
+ validUntil: Date.now() + 300000, // 5 minutes from now
1217
+ metadata: {
1218
+ order: intent.order,
1219
+ settlementContract: intent.settlementContract ?? '',
1220
+ chainId: quoteResponse.quote.srcChainId,
1221
+ bridgeQuote: quoteResponse,
1222
+ },
1223
+ };
1224
+ }, _BridgeStatusController_mapIntentOrderStatusToTransactionStatus = function _BridgeStatusController_mapIntentOrderStatusToTransactionStatus(intentStatus) {
1225
+ switch (intentStatus) {
1226
+ case IntentOrderStatus.PENDING:
1227
+ case IntentOrderStatus.SUBMITTED:
1228
+ return TransactionStatus.submitted;
1229
+ case IntentOrderStatus.CONFIRMED:
1230
+ case IntentOrderStatus.COMPLETED:
1231
+ return TransactionStatus.confirmed;
1232
+ case IntentOrderStatus.FAILED:
1233
+ case IntentOrderStatus.EXPIRED:
1234
+ return TransactionStatus.failed;
1235
+ default:
1236
+ return TransactionStatus.submitted;
1237
+ }
850
1238
  };
851
1239
  //# sourceMappingURL=bridge-status-controller.mjs.map