@metamask-previews/bridge-status-controller 42.0.0-preview-cab2ca5 → 42.0.0-preview-c76a00c1

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.
@@ -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_handleSolanaTx, _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_fetchCowOrderStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_handleSolanaTx, _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");
@@ -25,6 +25,20 @@ const gas_1 = require("./utils/gas.cjs");
25
25
  const metrics_1 = require("./utils/metrics.cjs");
26
26
  const transaction_1 = require("./utils/transaction.cjs");
27
27
  const transaction_2 = require("./utils/transaction.cjs");
28
+ // CoW intent: API base and network path mapping (adjust as needed)
29
+ const COW_API_BASE = 'https://api.cow.fi';
30
+ const COW_NETWORK_PATHS = {
31
+ // Ethereum Mainnet
32
+ 1: 'mainnet',
33
+ // Arbitrum One
34
+ 42161: 'arbitrum_one',
35
+ // Base
36
+ 8453: 'base',
37
+ // Avalanche C-Chain
38
+ 43114: 'avalanche',
39
+ // Polygon PoS
40
+ 137: 'polygon',
41
+ };
28
42
  const metadata = {
29
43
  // We want to persist the bridge status state so that we can show the proper data for the Activity list
30
44
  // basically match the behavior of TransactionController
@@ -179,6 +193,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
179
193
  // We know it's in progress but not the exact status yet
180
194
  const txHistoryItem = {
181
195
  txMetaId: bridgeTxMeta.id,
196
+ originalTransactionId: bridgeTxMeta
197
+ .originalTransactionId || bridgeTxMeta.id,
182
198
  batchId: bridgeTxMeta.batchId,
183
199
  quote: quoteResponse.quote,
184
200
  startTime,
@@ -223,8 +239,9 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
223
239
  return;
224
240
  }
225
241
  const { quote } = txHistoryItem;
242
+ const isIntent = txId.startsWith('intent:');
226
243
  const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quote.srcChainId, quote.destChainId);
227
- if (isBridgeTx) {
244
+ if (isBridgeTx || isIntent) {
228
245
  __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[txId] = this.startPolling({
229
246
  bridgeTxMetaId: txId,
230
247
  });
@@ -283,6 +300,11 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
283
300
  });
284
301
  _BridgeStatusController_fetchBridgeTxStatus.set(this, async ({ bridgeTxMetaId, }) => {
285
302
  const { txHistory } = this.state;
303
+ // Intent-based items: poll CoW API instead of Bridge API
304
+ if (bridgeTxMetaId.startsWith('intent:')) {
305
+ await __classPrivateFieldGet(this, _BridgeStatusController_fetchCowOrderStatus, "f").call(this, { bridgeTxMetaId });
306
+ return;
307
+ }
286
308
  if ((0, bridge_status_1.shouldSkipFetchDueToFetchFailures)(txHistory[bridgeTxMetaId]?.attempts)) {
287
309
  return;
288
310
  }
@@ -334,8 +356,174 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
334
356
  }
335
357
  }
336
358
  }
337
- catch (e) {
338
- console.warn('Failed to fetch bridge tx status', e);
359
+ catch (error) {
360
+ console.warn('Failed to fetch bridge tx status', error);
361
+ __classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
362
+ }
363
+ });
364
+ _BridgeStatusController_fetchCowOrderStatus.set(this, async ({ bridgeTxMetaId, }) => {
365
+ const { txHistory } = this.state;
366
+ const historyItem = txHistory[bridgeTxMetaId];
367
+ if (!historyItem) {
368
+ return;
369
+ }
370
+ // Backoff handling
371
+ if ((0, bridge_status_1.shouldSkipFetchDueToFetchFailures)(historyItem.attempts)) {
372
+ return;
373
+ }
374
+ const orderUid = bridgeTxMetaId.replace(/^intent:/u, '');
375
+ const { srcChainId } = historyItem.quote;
376
+ const networkPath = COW_NETWORK_PATHS[srcChainId];
377
+ if (!networkPath) {
378
+ // Unsupported mapping: stop polling with failure
379
+ this.update((state) => {
380
+ state.txHistory[bridgeTxMetaId].status = {
381
+ status: bridge_controller_1.StatusTypes.FAILED,
382
+ srcChain: {
383
+ chainId: srcChainId,
384
+ txHash: '',
385
+ },
386
+ };
387
+ });
388
+ return;
389
+ }
390
+ try {
391
+ const url = `${COW_API_BASE}/${networkPath}/api/v1/orders/${orderUid}`;
392
+ const res = await __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f").call(this, url, { method: 'GET' });
393
+ // CoW API status enum mapping
394
+ const rawStatus = typeof res === 'object' && res !== null && 'status' in res
395
+ ? (res.status ?? '')
396
+ : '';
397
+ const isComplete = rawStatus === 'fulfilled';
398
+ const isFailed = ['cancelled', 'expired'].includes(rawStatus);
399
+ const isPending = ['presignaturePending', 'open'].includes(rawStatus);
400
+ // Try to find a tx hash in common fields
401
+ let txHash = '';
402
+ let allHashes = [];
403
+ if (isComplete) {
404
+ // Prefer authoritative trades endpoint for one or multiple fills
405
+ const tradesUrl = `${COW_API_BASE}/${networkPath}/api/v1/trades?orderUid=${orderUid}`;
406
+ const trades = (await __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f").call(this, tradesUrl, { method: 'GET' })) ?? [];
407
+ allHashes = Array.isArray(trades)
408
+ ? trades
409
+ .map((t) => t?.txHash || t?.transactionHash)
410
+ .filter((h) => typeof h === 'string' && h.length > 0)
411
+ : [];
412
+ // Fallback to any hash on order if trades missing
413
+ if (allHashes.length === 0) {
414
+ const possible = [
415
+ res.txHash,
416
+ res.transactionHash,
417
+ res.executedTransaction,
418
+ res
419
+ .executedTransactionHash,
420
+ ].filter((h) => typeof h === 'string' && h.length > 0);
421
+ allHashes = possible;
422
+ }
423
+ txHash = allHashes[allHashes.length - 1] || '';
424
+ }
425
+ let statusType;
426
+ if (isComplete) {
427
+ statusType = bridge_controller_1.StatusTypes.COMPLETE;
428
+ }
429
+ else if (isFailed) {
430
+ statusType = bridge_controller_1.StatusTypes.FAILED;
431
+ }
432
+ else if (isPending) {
433
+ statusType = bridge_controller_1.StatusTypes.PENDING;
434
+ }
435
+ else {
436
+ statusType = bridge_controller_1.StatusTypes.PENDING; // Default to pending for unknown statuses
437
+ }
438
+ const newStatus = {
439
+ status: statusType,
440
+ srcChain: {
441
+ chainId: srcChainId,
442
+ txHash: txHash || historyItem.status.srcChain.txHash || '',
443
+ },
444
+ };
445
+ const newBridgeHistoryItem = {
446
+ ...historyItem,
447
+ status: newStatus,
448
+ completionTime: newStatus.status === bridge_controller_1.StatusTypes.COMPLETE ||
449
+ newStatus.status === bridge_controller_1.StatusTypes.FAILED
450
+ ? Date.now()
451
+ : undefined,
452
+ attempts: undefined,
453
+ srcTxHashes: allHashes.length > 0
454
+ ? Array.from(new Set([...(historyItem.srcTxHashes ?? []), ...allHashes]))
455
+ : historyItem.srcTxHashes,
456
+ };
457
+ this.update((state) => {
458
+ state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;
459
+ });
460
+ // Update the actual transaction in TransactionController to sync with CoW status
461
+ // Use the original transaction ID (not the intent: prefixed bridge history key)
462
+ const originalTxId = historyItem
463
+ .originalTransactionId || historyItem.txMetaId;
464
+ if (originalTxId && !originalTxId.startsWith('intent:')) {
465
+ try {
466
+ let transactionStatus;
467
+ if (isComplete) {
468
+ transactionStatus = transaction_controller_1.TransactionStatus.confirmed;
469
+ }
470
+ else if (isFailed) {
471
+ transactionStatus = transaction_controller_1.TransactionStatus.failed;
472
+ }
473
+ else if (isPending) {
474
+ transactionStatus = transaction_controller_1.TransactionStatus.submitted;
475
+ }
476
+ else {
477
+ transactionStatus = transaction_controller_1.TransactionStatus.submitted; // Default to submitted for unknown statuses
478
+ }
479
+ // Merge with existing TransactionMeta to avoid wiping required fields
480
+ const { transactions } = this.messagingSystem.call('TransactionController:getState');
481
+ const existingTxMeta = transactions.find((t) => t.id === originalTxId);
482
+ if (!existingTxMeta) {
483
+ console.warn('📝 [fetchCowOrderStatus] Skipping update; transaction not found', { originalTxId, bridgeHistoryKey: bridgeTxMetaId });
484
+ }
485
+ else {
486
+ const updatedTxMeta = {
487
+ ...existingTxMeta,
488
+ status: transactionStatus,
489
+ ...(txHash ? { hash: txHash } : {}),
490
+ ...(txHash
491
+ ? {
492
+ txReceipt: {
493
+ ...existingTxMeta.txReceipt,
494
+ transactionHash: txHash,
495
+ status: (isComplete ? '0x1' : '0x0'),
496
+ },
497
+ }
498
+ : {}),
499
+ };
500
+ __classPrivateFieldGet(this, _BridgeStatusController_updateTransactionFn, "f").call(this, updatedTxMeta, `BridgeStatusController - CoW order status updated: ${rawStatus}`);
501
+ }
502
+ }
503
+ catch (error) {
504
+ console.error('📝 [fetchCowOrderStatus] Failed to update transaction status', {
505
+ originalTxId,
506
+ bridgeHistoryKey: bridgeTxMetaId,
507
+ error,
508
+ });
509
+ }
510
+ }
511
+ const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
512
+ const isFinal = newStatus.status === bridge_controller_1.StatusTypes.COMPLETE ||
513
+ newStatus.status === bridge_controller_1.StatusTypes.FAILED;
514
+ if (isFinal && pollingToken) {
515
+ this.stopPollingByPollingToken(pollingToken);
516
+ delete __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
517
+ if (newStatus.status === bridge_controller_1.StatusTypes.COMPLETE) {
518
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Completed, bridgeTxMetaId);
519
+ }
520
+ else if (newStatus.status === bridge_controller_1.StatusTypes.FAILED) {
521
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Failed, bridgeTxMetaId);
522
+ }
523
+ }
524
+ }
525
+ catch {
526
+ // Network or API error: apply backoff
339
527
  __classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
340
528
  }
341
529
  });
@@ -420,6 +608,36 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
420
608
  }
421
609
  return finalTransactionMeta;
422
610
  });
611
+ // Waits until a given transaction (by id) reaches confirmed/finalized status or fails/times out.
612
+ _BridgeStatusController_waitForTxConfirmation.set(this, async (txId, { timeoutMs = 5 * 60000, // 5 minutes default
613
+ pollMs = 2000, } = {}) => {
614
+ const start = Date.now();
615
+ // Poll the TransactionController state for status changes
616
+ // We intentionally keep this simple to avoid extra wiring/subscriptions in this controller
617
+ // and because we only need it for the rare intent+approval path.
618
+ while (true) {
619
+ const { transactions } = this.messagingSystem.call('TransactionController:getState');
620
+ const meta = transactions.find((t) => t.id === txId);
621
+ if (meta) {
622
+ // Treat both 'confirmed' and 'finalized' as success to match TC lifecycle
623
+ if (meta.status === transaction_controller_1.TransactionStatus.confirmed ||
624
+ // Some environments move directly to finalized
625
+ transaction_controller_1.TransactionStatus.finalized ===
626
+ meta.status) {
627
+ return meta;
628
+ }
629
+ if (meta.status === transaction_controller_1.TransactionStatus.failed ||
630
+ meta.status === transaction_controller_1.TransactionStatus.dropped ||
631
+ meta.status === transaction_controller_1.TransactionStatus.rejected) {
632
+ throw new Error('Approval transaction did not confirm');
633
+ }
634
+ }
635
+ if (Date.now() - start > timeoutMs) {
636
+ throw new Error('Timed out waiting for approval confirmation');
637
+ }
638
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
639
+ }
640
+ });
423
641
  _BridgeStatusController_handleApprovalTx.set(this, async (isBridgeTx, quoteResponse, requireApproval) => {
424
642
  const { approval } = quoteResponse;
425
643
  if (approval) {
@@ -471,11 +689,17 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
471
689
  type: transactionType,
472
690
  origin: 'metamask',
473
691
  };
692
+ // Exclude gasLimit from trade to avoid type issues (it can be null)
693
+ const { gasLimit: tradeGasLimit, ...tradeWithoutGasLimit } = trade;
474
694
  const transactionParams = {
475
- ...trade,
695
+ ...tradeWithoutGasLimit,
476
696
  chainId: hexChainId,
477
- gasLimit: trade.gasLimit?.toString(),
478
- gas: trade.gasLimit?.toString(),
697
+ // Only add gasLimit and gas if they're valid (not undefined/null/zero)
698
+ ...(tradeGasLimit &&
699
+ tradeGasLimit !== 0 && {
700
+ gasLimit: tradeGasLimit.toString(),
701
+ gas: tradeGasLimit.toString(),
702
+ }),
479
703
  };
480
704
  const transactionParamsWithMaxGas = {
481
705
  ...transactionParams,
@@ -504,7 +728,11 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
504
728
  networkGasFeeEstimates: gasFeeEstimates,
505
729
  txGasFeeEstimates,
506
730
  });
507
- const maxGasLimit = (0, controller_utils_1.toHex)(transactionParams.gas ?? 0);
731
+ // Let the TransactionController handle gas limit estimation when no gas is provided
732
+ // This fixes the issue where approval transactions had zero gas
733
+ const maxGasLimit = transactionParams.gas
734
+ ? (0, controller_utils_1.toHex)(transactionParams.gas)
735
+ : undefined;
508
736
  return {
509
737
  maxFeePerGas,
510
738
  maxPriorityFeePerGas,
@@ -661,6 +889,211 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
661
889
  }
662
890
  return txMeta;
663
891
  };
892
+ /**
893
+ * UI-signed intent submission (fast path): the UI generates the EIP-712 signature and calls this with the raw signature.
894
+ * Here we POST the order to the intent backend (e.g., CoW) and create a synthetic history entry for UX.
895
+ *
896
+ * @param params - Object containing intent submission parameters
897
+ * @param params.quoteResponse - Quote carrying intent data
898
+ * @param params.signature - Hex signature produced by eth_signTypedData_v4
899
+ * @param params.accountAddress - The EOA submitting the order
900
+ * @returns A lightweight TransactionMeta-like object for history linking
901
+ */
902
+ this.submitIntent = async (params) => {
903
+ const { quoteResponse, signature, accountAddress } = params;
904
+ // Build pre-confirmation properties for error tracking parity with submitTx
905
+ const account = this.messagingSystem.call('AccountsController:getAccountByAddress', accountAddress);
906
+ const isHardwareAccount = Boolean(account) && (0, bridge_controller_1.isHardwareWallet)(account);
907
+ const preConfirmationProperties = (0, metrics_1.getPreConfirmationPropertiesFromQuote)(quoteResponse, false, isHardwareAccount);
908
+ try {
909
+ const { intent } = quoteResponse
910
+ .quote;
911
+ if (!intent || intent.protocol !== 'cowswap') {
912
+ throw new Error('submitIntent: missing or unsupported intent');
913
+ }
914
+ // If backend provided an approval tx for this intent quote, submit it first (on-chain),
915
+ // then proceed with off-chain intent submission.
916
+ let approvalTxId;
917
+ if (quoteResponse.approval) {
918
+ const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
919
+ // Handle approval silently for better UX in intent flows
920
+ const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, isBridgeTx, quoteResponse,
921
+ /* requireApproval */ false);
922
+ approvalTxId = approvalTxMeta?.id;
923
+ // Optionally wait for approval confirmation with timeout and graceful fallback
924
+ // CoW order can be created before allowance is mined, but waiting helps avoid MEV issues
925
+ if (approvalTxId) {
926
+ try {
927
+ // Wait with a shorter timeout and continue if it fails
928
+ await __classPrivateFieldGet(this, _BridgeStatusController_waitForTxConfirmation, "f").call(this, approvalTxId, {
929
+ timeoutMs: 30000,
930
+ pollMs: 3000, // Poll less frequently to avoid rate limits
931
+ });
932
+ }
933
+ catch (error) {
934
+ // Log but don't throw - continue with CoW order submission
935
+ console.warn('Approval confirmation failed, continuing with intent submission:', error);
936
+ }
937
+ }
938
+ }
939
+ // Map chainId to CoW API server path (prod)
940
+ const chainId = quoteResponse.quote.srcChainId;
941
+ const serverPath = COW_NETWORK_PATHS[chainId];
942
+ if (!serverPath) {
943
+ throw new Error(`submitIntent: unsupported chainId for CoW intents: ${chainId}`);
944
+ }
945
+ // Build OrderCreation payload (simplified)
946
+ const orderBody = {
947
+ ...intent.order,
948
+ feeAmount: '0',
949
+ from: accountAddress,
950
+ signature,
951
+ signingScheme: 'eip712',
952
+ };
953
+ // POST to CoW prod
954
+ const url = `https://api.cow.fi/${serverPath}/api/v1/orders`;
955
+ const res = await __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f").call(this, url, {
956
+ method: 'POST',
957
+ headers: { 'Content-Type': 'application/json' },
958
+ body: JSON.stringify(orderBody),
959
+ });
960
+ const orderUid = typeof res === 'string'
961
+ ? res
962
+ : (res?.uid ??
963
+ res
964
+ ?.orderUid ??
965
+ res?.id);
966
+ if (!orderUid) {
967
+ throw new Error('submitIntent: failed to submit order');
968
+ }
969
+ // Get initial order status from CoW API
970
+ let initialOrderStatus = 'open'; // Default status
971
+ try {
972
+ const orderStatusUrl = `${COW_API_BASE}/${serverPath}/api/v1/orders/${orderUid}`;
973
+ const orderStatusRes = await __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f").call(this, orderStatusUrl, {
974
+ method: 'GET',
975
+ });
976
+ initialOrderStatus =
977
+ orderStatusRes?.status ?? 'open';
978
+ }
979
+ catch (error) {
980
+ console.warn('📝 [submitIntent] Failed to get initial order status, using default:', error);
981
+ }
982
+ // Determine transaction type: swap for same-chain, bridge for cross-chain
983
+ const isCrossChainTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
984
+ const transactionType = isCrossChainTx
985
+ ? transaction_controller_1.TransactionType.bridge
986
+ : transaction_controller_1.TransactionType.swap;
987
+ // Create actual transaction in Transaction Controller first
988
+ const networkClientId = this.messagingSystem.call('NetworkController:findNetworkClientIdByChainId', (0, bridge_controller_1.formatChainIdToHex)(chainId));
989
+ const intentTransactionParams = {
990
+ chainId: (0, bridge_controller_1.formatChainIdToHex)(chainId),
991
+ from: accountAddress,
992
+ to: intent.settlementContract ||
993
+ '0x9008D19f58AAbd9eD0D60971565AA8510560ab41',
994
+ data: `0x${orderUid.slice(-8)}`,
995
+ value: '0x0',
996
+ gas: '0x5208',
997
+ gasPrice: '0x3b9aca00', // 1 Gwei - will be converted to EIP-1559 fees if network supports it
998
+ };
999
+ const { transactionMeta: txMetaPromise } = await __classPrivateFieldGet(this, _BridgeStatusController_addTransactionFn, "f").call(this, intentTransactionParams, {
1000
+ origin: 'metamask',
1001
+ actionId: (0, transaction_2.generateActionId)(),
1002
+ requireApproval: false,
1003
+ networkClientId,
1004
+ type: transactionType,
1005
+ swaps: {
1006
+ meta: {
1007
+ // Add token symbols from quoteResponse for proper display
1008
+ sourceTokenSymbol: quoteResponse.quote.srcAsset.symbol,
1009
+ destinationTokenSymbol: quoteResponse.quote.destAsset.symbol,
1010
+ sourceTokenAmount: quoteResponse.quote.srcTokenAmount,
1011
+ destinationTokenAmount: quoteResponse.quote.destTokenAmount,
1012
+ sourceTokenDecimals: quoteResponse.quote.srcAsset.decimals,
1013
+ destinationTokenDecimals: quoteResponse.quote.destAsset.decimals,
1014
+ sourceTokenAddress: quoteResponse.quote.srcAsset.address,
1015
+ destinationTokenAddress: quoteResponse.quote.destAsset.address,
1016
+ swapTokenValue: quoteResponse.sentAmount.amount,
1017
+ approvalTxId,
1018
+ swapMetaData: {
1019
+ isIntentTx: true,
1020
+ orderUid,
1021
+ intentType: isCrossChainTx ? 'bridge' : 'swap',
1022
+ },
1023
+ },
1024
+ },
1025
+ });
1026
+ const intentTxMeta = txMetaPromise;
1027
+ // Map initial CoW order status to TransactionController status
1028
+ const isComplete = initialOrderStatus === 'fulfilled';
1029
+ const isFailed = ['cancelled', 'expired'].includes(initialOrderStatus);
1030
+ const isPending = ['presignaturePending', 'open'].includes(initialOrderStatus);
1031
+ let initialTransactionStatus;
1032
+ if (isComplete) {
1033
+ initialTransactionStatus = transaction_controller_1.TransactionStatus.confirmed;
1034
+ }
1035
+ else if (isFailed) {
1036
+ initialTransactionStatus = transaction_controller_1.TransactionStatus.failed;
1037
+ }
1038
+ else if (isPending) {
1039
+ initialTransactionStatus = transaction_controller_1.TransactionStatus.submitted;
1040
+ }
1041
+ else {
1042
+ initialTransactionStatus = transaction_controller_1.TransactionStatus.submitted;
1043
+ }
1044
+ // Update transaction with proper initial status based on CoW order
1045
+ const statusUpdatedTxMeta = {
1046
+ ...intentTxMeta,
1047
+ status: initialTransactionStatus,
1048
+ };
1049
+ __classPrivateFieldGet(this, _BridgeStatusController_updateTransactionFn, "f").call(this, statusUpdatedTxMeta, `BridgeStatusController - Initial CoW order status: ${initialOrderStatus}`);
1050
+ // Update with actual transaction metadata
1051
+ const syntheticMeta = {
1052
+ ...statusUpdatedTxMeta,
1053
+ isIntentTx: true,
1054
+ orderUid,
1055
+ intentType: isCrossChainTx ? 'bridge' : 'swap',
1056
+ };
1057
+ // Record in bridge history with actual transaction metadata
1058
+ try {
1059
+ // Use intent: prefix for CoW transactions to route to CoW API
1060
+ const bridgeHistoryKey = `intent:${orderUid}`;
1061
+ // Create a bridge transaction metadata that includes the original txId
1062
+ const bridgeTxMetaForHistory = {
1063
+ ...syntheticMeta,
1064
+ id: bridgeHistoryKey,
1065
+ originalTransactionId: syntheticMeta.id, // Keep original txId for TransactionController updates
1066
+ };
1067
+ __classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
1068
+ accountAddress,
1069
+ bridgeTxMeta: bridgeTxMetaForHistory,
1070
+ statusRequest: {
1071
+ ...(0, transaction_1.getStatusRequestParams)(quoteResponse),
1072
+ srcTxHash: syntheticMeta.hash || '',
1073
+ },
1074
+ quoteResponse,
1075
+ slippagePercentage: 0,
1076
+ isStxEnabled: false,
1077
+ approvalTxId,
1078
+ });
1079
+ // Debug: Check if the bridge history was added
1080
+ // Start polling using the intent: prefixed key to route to CoW API
1081
+ __classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, bridgeHistoryKey);
1082
+ }
1083
+ catch (error) {
1084
+ console.error('📝 [submitIntent] Failed to add to bridge history', error);
1085
+ // non-fatal but log the error
1086
+ }
1087
+ return syntheticMeta;
1088
+ }
1089
+ catch (error) {
1090
+ __classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, bridge_controller_1.UnifiedSwapBridgeEventName.Failed, undefined, {
1091
+ error_message: error?.message,
1092
+ ...preConfirmationProperties,
1093
+ });
1094
+ throw error;
1095
+ }
1096
+ };
664
1097
  /**
665
1098
  * Tracks post-submission events for a cross-chain swap based on the history item
666
1099
  *
@@ -684,8 +1117,8 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
684
1117
  }
685
1118
  const selectedAccount = this.messagingSystem.call('AccountsController:getAccountByAddress', historyItem.account);
686
1119
  const { transactions } = this.messagingSystem.call('TransactionController:getState');
687
- const txMeta = transactions?.find(({ id }) => id === txMetaId);
688
- const approvalTxMeta = transactions?.find(({ id }) => id === historyItem.approvalTxId);
1120
+ const txMeta = transactions?.find((t) => t.id === txMetaId);
1121
+ const approvalTxMeta = transactions?.find((t) => t.id === historyItem.approvalTxId);
689
1122
  const requestParamProperties = (0, metrics_1.getRequestParamFromHistory)(historyItem);
690
1123
  if (eventName === bridge_controller_1.UnifiedSwapBridgeEventName.StatusValidationFailed) {
691
1124
  const { chain_id_source, chain_id_destination, token_address_source, token_address_destination, } = requestParamProperties;
@@ -725,12 +1158,19 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
725
1158
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
726
1159
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
727
1160
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this));
1161
+ this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:submitIntent`, this.submitIntent.bind(this));
728
1162
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:restartPollingForFailedAttempts`, this.restartPollingForFailedAttempts.bind(this));
729
1163
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:getBridgeHistoryItemByTxMetaId`, this.getBridgeHistoryItemByTxMetaId.bind(this));
730
1164
  // Set interval
731
1165
  this.setIntervalLength(constants_1.REFRESH_INTERVAL_MS);
732
1166
  this.messagingSystem.subscribe('TransactionController:transactionFailed', ({ transactionMeta }) => {
733
1167
  const { type, status, id } = transactionMeta;
1168
+ // Skip intent transactions - they have their own tracking via CoW API
1169
+ // Skip intent transactions - they have their own tracking via CoW API
1170
+ if (transactionMeta
1171
+ .swapMetaData?.isIntentTx) {
1172
+ return;
1173
+ }
734
1174
  if (type &&
735
1175
  [
736
1176
  transaction_controller_1.TransactionType.bridge,
@@ -767,7 +1207,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
767
1207
  }
768
1208
  }
769
1209
  exports.BridgeStatusController = BridgeStatusController;
770
- _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_handleSolanaTx = 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() {
1210
+ _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_fetchCowOrderStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_handleSolanaTx = 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() {
771
1211
  return this.messagingSystem.call('AccountsController:getSelectedMultichainAccount');
772
1212
  };
773
1213
  //# sourceMappingURL=bridge-status-controller.cjs.map