@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.
- package/CHANGELOG.md +23 -1
- package/dist/bridge-status-controller.cjs +344 -18
- package/dist/bridge-status-controller.cjs.map +1 -1
- package/dist/bridge-status-controller.d.cts +16 -1
- package/dist/bridge-status-controller.d.cts.map +1 -1
- package/dist/bridge-status-controller.d.mts +16 -1
- package/dist/bridge-status-controller.d.mts.map +1 -1
- package/dist/bridge-status-controller.mjs +344 -18
- package/dist/bridge-status-controller.mjs.map +1 -1
- package/dist/types.cjs +9 -7
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +26 -16
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +26 -16
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +9 -7
- package/dist/types.mjs.map +1 -1
- package/dist/utils/gas.cjs +2 -1
- package/dist/utils/gas.cjs.map +1 -1
- package/dist/utils/gas.d.cts.map +1 -1
- package/dist/utils/gas.d.mts.map +1 -1
- package/dist/utils/gas.mjs +2 -1
- package/dist/utils/gas.mjs.map +1 -1
- package/dist/utils/intent-api.cjs +90 -0
- package/dist/utils/intent-api.cjs.map +1 -0
- package/dist/utils/intent-api.d.cts +26 -0
- package/dist/utils/intent-api.d.cts.map +1 -0
- package/dist/utils/intent-api.d.mts +26 -0
- package/dist/utils/intent-api.d.mts.map +1 -0
- package/dist/utils/intent-api.mjs +84 -0
- package/dist/utils/intent-api.mjs.map +1 -0
- package/dist/utils/transaction.d.cts +21 -2
- package/dist/utils/transaction.d.cts.map +1 -1
- package/dist/utils/transaction.d.mts +21 -2
- package/dist/utils/transaction.d.mts.map +1 -1
- package/dist/utils/validators.cjs +23 -1
- package/dist/utils/validators.cjs.map +1 -1
- package/dist/utils/validators.d.cts +51 -0
- package/dist/utils/validators.d.cts.map +1 -1
- package/dist/utils/validators.d.mts +51 -0
- package/dist/utils/validators.d.mts.map +1 -1
- package/dist/utils/validators.mjs +22 -1
- package/dist/utils/validators.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -9,7 +9,7 @@ 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_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";
|
|
@@ -19,8 +19,10 @@ import { BRIDGE_PROD_API_BASE_URL, BRIDGE_STATUS_CONTROLLER_NAME, DEFAULT_BRIDGE
|
|
|
19
19
|
import { BridgeClientId } from "./types.mjs";
|
|
20
20
|
import { fetchBridgeTxStatus, getStatusRequestWithSrcTxHash, shouldSkipFetchDueToFetchFailures } from "./utils/bridge-status.mjs";
|
|
21
21
|
import { getTxGasEstimates } from "./utils/gas.mjs";
|
|
22
|
+
import { IntentApiImpl, mapIntentOrderStatusToTransactionStatus } from "./utils/intent-api.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,11 +348,38 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
338
348
|
}
|
|
339
349
|
}
|
|
340
350
|
}
|
|
341
|
-
catch (
|
|
342
|
-
console.warn('Failed to fetch bridge tx status',
|
|
351
|
+
catch (error) {
|
|
352
|
+
console.warn('Failed to fetch bridge tx status', error);
|
|
343
353
|
__classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
|
|
344
354
|
}
|
|
345
355
|
});
|
|
356
|
+
_BridgeStatusController_fetchIntentOrderStatus.set(this, async ({ bridgeTxMetaId, }) => {
|
|
357
|
+
/* c8 ignore start */
|
|
358
|
+
const { txHistory } = this.state;
|
|
359
|
+
const historyItem = txHistory[bridgeTxMetaId];
|
|
360
|
+
if (!historyItem) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
// Backoff handling
|
|
364
|
+
if (shouldSkipFetchDueToFetchFailures(historyItem.attempts)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const orderId = bridgeTxMetaId.replace(/^intent:/u, '');
|
|
369
|
+
const { srcChainId } = historyItem.quote;
|
|
370
|
+
// Extract provider name from order metadata or default to empty
|
|
371
|
+
const providerName = historyItem.quote.intent?.protocol ?? '';
|
|
372
|
+
const intentApi = new IntentApiImpl(__classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl, __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
|
|
373
|
+
const intentOrder = await intentApi.getOrderStatus(orderId, providerName, srcChainId.toString(), __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
|
|
374
|
+
// Update bridge history with intent order status
|
|
375
|
+
__classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_updateBridgeHistoryFromIntentOrder).call(this, bridgeTxMetaId, intentOrder, historyItem);
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
console.error('Failed to fetch intent order status:', error);
|
|
379
|
+
__classPrivateFieldGet(this, _BridgeStatusController_handleFetchFailure, "f").call(this, bridgeTxMetaId);
|
|
380
|
+
}
|
|
381
|
+
/* c8 ignore stop */
|
|
382
|
+
});
|
|
346
383
|
_BridgeStatusController_getSrcTxHash.set(this, (bridgeTxMetaId) => {
|
|
347
384
|
const { txHistory } = this.state;
|
|
348
385
|
// Prefer the srcTxHash from bridgeStatusState so we don't have to l ook up in TransactionController
|
|
@@ -430,6 +467,35 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
430
467
|
}
|
|
431
468
|
return finalTransactionMeta;
|
|
432
469
|
});
|
|
470
|
+
// Waits until a given transaction (by id) reaches confirmed/finalized status or fails/times out.
|
|
471
|
+
_BridgeStatusController_waitForTxConfirmation.set(this, async (txId, { timeoutMs = 5 * 60000, // 5 minutes default
|
|
472
|
+
pollMs = 3000, } = {}) => {
|
|
473
|
+
/* c8 ignore start */
|
|
474
|
+
const start = Date.now();
|
|
475
|
+
// Poll the TransactionController state for status changes
|
|
476
|
+
// We intentionally keep this simple to avoid extra wiring/subscriptions in this controller
|
|
477
|
+
// and because we only need it for the rare intent+approval path.
|
|
478
|
+
while (true) {
|
|
479
|
+
const { transactions } = this.messenger.call('TransactionController:getState');
|
|
480
|
+
const meta = transactions.find((tx) => tx.id === txId);
|
|
481
|
+
if (meta) {
|
|
482
|
+
// Treat both 'confirmed' and 'finalized' as success to match TC lifecycle
|
|
483
|
+
if (meta.status === TransactionStatus.confirmed) {
|
|
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
|
+
/* c8 ignore stop */
|
|
498
|
+
});
|
|
433
499
|
_BridgeStatusController_handleApprovalTx.set(this, async (isBridgeTx, srcChainId, approval, resetApproval, requireApproval) => {
|
|
434
500
|
if (approval) {
|
|
435
501
|
const approveTx = async () => {
|
|
@@ -483,11 +549,17 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
483
549
|
type: transactionType,
|
|
484
550
|
origin: 'metamask',
|
|
485
551
|
};
|
|
552
|
+
// Exclude gasLimit from trade to avoid type issues (it can be null)
|
|
553
|
+
const { gasLimit: tradeGasLimit, ...tradeWithoutGasLimit } = trade;
|
|
486
554
|
const transactionParams = {
|
|
487
|
-
...
|
|
555
|
+
...tradeWithoutGasLimit,
|
|
488
556
|
chainId: hexChainId,
|
|
489
|
-
gasLimit
|
|
490
|
-
|
|
557
|
+
// Only add gasLimit and gas if they're valid (not undefined/null/zero)
|
|
558
|
+
...(tradeGasLimit &&
|
|
559
|
+
tradeGasLimit !== 0 && {
|
|
560
|
+
gasLimit: tradeGasLimit.toString(),
|
|
561
|
+
gas: tradeGasLimit.toString(),
|
|
562
|
+
}),
|
|
491
563
|
};
|
|
492
564
|
const transactionParamsWithMaxGas = {
|
|
493
565
|
...transactionParams,
|
|
@@ -505,14 +577,14 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
505
577
|
}
|
|
506
578
|
});
|
|
507
579
|
_BridgeStatusController_calculateGasFees.set(this, async (transactionParams, networkClientId, chainId, txFee) => {
|
|
508
|
-
const
|
|
580
|
+
const { gas } = transactionParams;
|
|
509
581
|
// If txFee is provided (gasIncluded case), use the quote's gas fees
|
|
510
582
|
// Convert to hex since txFee values from the quote are decimal strings
|
|
511
583
|
if (txFee) {
|
|
512
584
|
return {
|
|
513
585
|
maxFeePerGas: toHex(txFee.maxFeePerGas ?? 0),
|
|
514
586
|
maxPriorityFeePerGas: toHex(txFee.maxPriorityFeePerGas ?? 0),
|
|
515
|
-
gas:
|
|
587
|
+
gas: gas ? toHex(gas) : undefined,
|
|
516
588
|
};
|
|
517
589
|
}
|
|
518
590
|
const { gasFeeEstimates } = this.messenger.call('GasFeeController:getState');
|
|
@@ -528,7 +600,7 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
528
600
|
return {
|
|
529
601
|
maxFeePerGas,
|
|
530
602
|
maxPriorityFeePerGas,
|
|
531
|
-
gas:
|
|
603
|
+
gas: gas ? toHex(gas) : undefined,
|
|
532
604
|
};
|
|
533
605
|
});
|
|
534
606
|
/**
|
|
@@ -734,6 +806,139 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
734
806
|
}
|
|
735
807
|
return txMeta;
|
|
736
808
|
};
|
|
809
|
+
/**
|
|
810
|
+
* UI-signed intent submission (fast path): the UI generates the EIP-712 signature and calls this with the raw signature.
|
|
811
|
+
* Here we submit the order to the intent provider and create a synthetic history entry for UX.
|
|
812
|
+
*
|
|
813
|
+
* @param params - Object containing intent submission parameters
|
|
814
|
+
* @param params.quoteResponse - Quote carrying intent data
|
|
815
|
+
* @param params.signature - Hex signature produced by eth_signTypedData_v4
|
|
816
|
+
* @param params.accountAddress - The EOA submitting the order
|
|
817
|
+
* @returns A lightweight TransactionMeta-like object for history linking
|
|
818
|
+
*/
|
|
819
|
+
this.submitIntent = async (params) => {
|
|
820
|
+
const { quoteResponse, signature, accountAddress } = params;
|
|
821
|
+
this.messenger.call('BridgeController:stopPollingForQuotes', AbortReason.TransactionSubmitted);
|
|
822
|
+
// Build pre-confirmation properties for error tracking parity with submitTx
|
|
823
|
+
const account = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this, accountAddress);
|
|
824
|
+
const isHardwareAccount = Boolean(account) && isHardwareWallet(account);
|
|
825
|
+
const preConfirmationProperties = getPreConfirmationPropertiesFromQuote(quoteResponse, false, isHardwareAccount);
|
|
826
|
+
try {
|
|
827
|
+
const { intent } = quoteResponse
|
|
828
|
+
.quote;
|
|
829
|
+
if (!intent) {
|
|
830
|
+
throw new Error('submitIntent: missing intent data');
|
|
831
|
+
}
|
|
832
|
+
// If backend provided an approval tx for this intent quote, submit it first (on-chain),
|
|
833
|
+
// then proceed with off-chain intent submission.
|
|
834
|
+
let approvalTxId;
|
|
835
|
+
if (quoteResponse.approval) {
|
|
836
|
+
const isBridgeTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
|
|
837
|
+
// Handle approval silently for better UX in intent flows
|
|
838
|
+
const approvalTxMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleApprovalTx, "f").call(this, isBridgeTx, quoteResponse.quote.srcChainId, quoteResponse.approval && isEvmTxData(quoteResponse.approval)
|
|
839
|
+
? quoteResponse.approval
|
|
840
|
+
: undefined, quoteResponse.resetApproval,
|
|
841
|
+
/* requireApproval */ false);
|
|
842
|
+
approvalTxId = approvalTxMeta?.id;
|
|
843
|
+
if (approvalTxId) {
|
|
844
|
+
await __classPrivateFieldGet(this, _BridgeStatusController_waitForTxConfirmation, "f").call(this, approvalTxId);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
const { srcChainId: chainId, requestId } = quoteResponse.quote;
|
|
848
|
+
const submissionParams = {
|
|
849
|
+
srcChainId: chainId.toString(),
|
|
850
|
+
quoteId: requestId,
|
|
851
|
+
signature,
|
|
852
|
+
order: intent.order,
|
|
853
|
+
userAddress: accountAddress,
|
|
854
|
+
aggregatorId: intent.protocol,
|
|
855
|
+
};
|
|
856
|
+
const intentApi = new IntentApiImpl(__classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl, __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
|
|
857
|
+
const intentOrder = await intentApi.submitIntent(submissionParams, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"));
|
|
858
|
+
const orderUid = intentOrder.id;
|
|
859
|
+
// Determine transaction type: swap for same-chain, bridge for cross-chain
|
|
860
|
+
const isCrossChainTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
|
|
861
|
+
const transactionType = isCrossChainTx
|
|
862
|
+
? TransactionType.bridge
|
|
863
|
+
: TransactionType.swap;
|
|
864
|
+
// Create actual transaction in Transaction Controller first
|
|
865
|
+
const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', formatChainIdToHex(chainId));
|
|
866
|
+
// This is a synthetic transaction whose purpose is to be able
|
|
867
|
+
// to track the order status via the history
|
|
868
|
+
const intentTransactionParams = {
|
|
869
|
+
chainId: formatChainIdToHex(chainId),
|
|
870
|
+
from: accountAddress,
|
|
871
|
+
to: intent.settlementContract ??
|
|
872
|
+
'0x9008D19f58AAbd9eD0D60971565AA8510560ab41', // Default settlement contract
|
|
873
|
+
data: `0x${orderUid.slice(-8)}`, // Use last 8 chars of orderUid to make each transaction unique
|
|
874
|
+
value: '0x0',
|
|
875
|
+
gas: '0x5208', // Minimal gas for display purposes
|
|
876
|
+
gasPrice: '0x3b9aca00', // 1 Gwei - will be converted to EIP-1559 fees if network supports it
|
|
877
|
+
};
|
|
878
|
+
const { transactionMeta: txMetaPromise } = await __classPrivateFieldGet(this, _BridgeStatusController_addTransactionFn, "f").call(this, intentTransactionParams, {
|
|
879
|
+
origin: 'metamask',
|
|
880
|
+
actionId: generateActionId(),
|
|
881
|
+
requireApproval: false,
|
|
882
|
+
isStateOnly: true,
|
|
883
|
+
networkClientId,
|
|
884
|
+
type: transactionType,
|
|
885
|
+
});
|
|
886
|
+
const intentTxMeta = txMetaPromise;
|
|
887
|
+
// Map intent order status to TransactionController status
|
|
888
|
+
const initialTransactionStatus = mapIntentOrderStatusToTransactionStatus(intentOrder.status);
|
|
889
|
+
// Update transaction with proper initial status based on intent order
|
|
890
|
+
const statusUpdatedTxMeta = {
|
|
891
|
+
...intentTxMeta,
|
|
892
|
+
status: initialTransactionStatus,
|
|
893
|
+
};
|
|
894
|
+
// Update with actual transaction metadata
|
|
895
|
+
const syntheticMeta = {
|
|
896
|
+
...statusUpdatedTxMeta,
|
|
897
|
+
isIntentTx: true,
|
|
898
|
+
orderUid,
|
|
899
|
+
intentType: isCrossChainTx ? 'bridge' : 'swap',
|
|
900
|
+
};
|
|
901
|
+
// Record in bridge history with actual transaction metadata
|
|
902
|
+
try {
|
|
903
|
+
// Use 'intent:' prefix for intent transactions
|
|
904
|
+
const bridgeHistoryKey = `intent:${orderUid}`;
|
|
905
|
+
// Create a bridge transaction metadata that includes the original txId
|
|
906
|
+
const bridgeTxMetaForHistory = {
|
|
907
|
+
...syntheticMeta,
|
|
908
|
+
id: bridgeHistoryKey, // Use intent: prefix for bridge history key
|
|
909
|
+
originalTransactionId: syntheticMeta.id, // Keep original txId for TransactionController updates
|
|
910
|
+
};
|
|
911
|
+
const startTime = Date.now();
|
|
912
|
+
__classPrivateFieldGet(this, _BridgeStatusController_addTxToHistory, "f").call(this, {
|
|
913
|
+
accountAddress,
|
|
914
|
+
bridgeTxMeta: bridgeTxMetaForHistory,
|
|
915
|
+
statusRequest: {
|
|
916
|
+
...getStatusRequestParams(quoteResponse),
|
|
917
|
+
srcTxHash: syntheticMeta.hash ?? '',
|
|
918
|
+
},
|
|
919
|
+
quoteResponse,
|
|
920
|
+
slippagePercentage: 0,
|
|
921
|
+
isStxEnabled: false,
|
|
922
|
+
approvalTxId,
|
|
923
|
+
startTime,
|
|
924
|
+
});
|
|
925
|
+
// Start polling using the intent: prefixed key to route to intent manager
|
|
926
|
+
__classPrivateFieldGet(this, _BridgeStatusController_startPollingForTxId, "f").call(this, bridgeHistoryKey);
|
|
927
|
+
}
|
|
928
|
+
catch (error) {
|
|
929
|
+
console.error('📝 [submitIntent] Failed to add to bridge history', error);
|
|
930
|
+
// non-fatal but log the error
|
|
931
|
+
}
|
|
932
|
+
return syntheticMeta;
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
__classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, undefined, {
|
|
936
|
+
error_message: error?.message,
|
|
937
|
+
...preConfirmationProperties,
|
|
938
|
+
});
|
|
939
|
+
throw error;
|
|
940
|
+
}
|
|
941
|
+
};
|
|
737
942
|
/**
|
|
738
943
|
* Tracks post-submission events for a cross-chain swap based on the history item
|
|
739
944
|
*
|
|
@@ -759,13 +964,12 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
759
964
|
const requestParamProperties = getRequestParamFromHistory(historyItem);
|
|
760
965
|
// Always publish StatusValidationFailed event, regardless of featureId
|
|
761
966
|
if (eventName === UnifiedSwapBridgeEventName.StatusValidationFailed) {
|
|
762
|
-
const { chain_id_source, chain_id_destination, token_address_source, token_address_destination, } = requestParamProperties;
|
|
763
967
|
this.messenger.call('BridgeController:trackUnifiedSwapBridgeEvent', eventName, {
|
|
764
968
|
...baseProperties,
|
|
765
|
-
chain_id_source,
|
|
766
|
-
chain_id_destination,
|
|
767
|
-
token_address_source,
|
|
768
|
-
token_address_destination,
|
|
969
|
+
chain_id_source: requestParamProperties.chain_id_source,
|
|
970
|
+
chain_id_destination: requestParamProperties.chain_id_destination,
|
|
971
|
+
token_address_source: requestParamProperties.token_address_source,
|
|
972
|
+
token_address_destination: requestParamProperties.token_address_destination,
|
|
769
973
|
refresh_count: historyItem.attempts?.counter ?? 0,
|
|
770
974
|
});
|
|
771
975
|
return;
|
|
@@ -776,8 +980,8 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
776
980
|
}
|
|
777
981
|
const selectedAccount = this.messenger.call('AccountsController:getAccountByAddress', historyItem.account);
|
|
778
982
|
const { transactions } = this.messenger.call('TransactionController:getState');
|
|
779
|
-
const txMeta = transactions?.find((
|
|
780
|
-
const approvalTxMeta = transactions?.find((
|
|
983
|
+
const txMeta = transactions?.find((tx) => tx.id === txMetaId);
|
|
984
|
+
const approvalTxMeta = transactions?.find((tx) => tx.id === historyItem.approvalTxId);
|
|
781
985
|
const requiredEventProperties = {
|
|
782
986
|
...baseProperties,
|
|
783
987
|
...requestParamProperties,
|
|
@@ -804,6 +1008,7 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
804
1008
|
this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
|
|
805
1009
|
this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
|
|
806
1010
|
this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this));
|
|
1011
|
+
this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:submitIntent`, this.submitIntent.bind(this));
|
|
807
1012
|
this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:restartPollingForFailedAttempts`, this.restartPollingForFailedAttempts.bind(this));
|
|
808
1013
|
this.messenger.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:getBridgeHistoryItemByTxMetaId`, this.getBridgeHistoryItemByTxMetaId.bind(this));
|
|
809
1014
|
// Set interval
|
|
@@ -845,7 +1050,128 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
|
|
|
845
1050
|
__classPrivateFieldGet(this, _BridgeStatusController_restartPollingForIncompleteHistoryItems, "f").call(this);
|
|
846
1051
|
}
|
|
847
1052
|
}
|
|
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) {
|
|
1053
|
+
_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
1054
|
return this.messenger.call('AccountsController:getAccountByAddress', accountAddress);
|
|
1055
|
+
}, _BridgeStatusController_updateBridgeHistoryFromIntentOrder = function _BridgeStatusController_updateBridgeHistoryFromIntentOrder(bridgeTxMetaId, intentOrder, historyItem) {
|
|
1056
|
+
const { srcChainId } = historyItem.quote;
|
|
1057
|
+
// Map intent order status to bridge status using enum values
|
|
1058
|
+
let statusType;
|
|
1059
|
+
const isComplete = [
|
|
1060
|
+
IntentOrderStatus.CONFIRMED,
|
|
1061
|
+
IntentOrderStatus.COMPLETED,
|
|
1062
|
+
].includes(intentOrder.status);
|
|
1063
|
+
const isFailed = [
|
|
1064
|
+
IntentOrderStatus.FAILED,
|
|
1065
|
+
IntentOrderStatus.EXPIRED,
|
|
1066
|
+
IntentOrderStatus.CANCELLED,
|
|
1067
|
+
].includes(intentOrder.status);
|
|
1068
|
+
const isPending = [IntentOrderStatus.PENDING].includes(intentOrder.status);
|
|
1069
|
+
const isSubmitted = [IntentOrderStatus.SUBMITTED].includes(intentOrder.status);
|
|
1070
|
+
if (isComplete) {
|
|
1071
|
+
statusType = StatusTypes.COMPLETE;
|
|
1072
|
+
}
|
|
1073
|
+
else if (isFailed) {
|
|
1074
|
+
statusType = StatusTypes.FAILED;
|
|
1075
|
+
}
|
|
1076
|
+
else if (isPending) {
|
|
1077
|
+
statusType = StatusTypes.PENDING;
|
|
1078
|
+
}
|
|
1079
|
+
else if (isSubmitted) {
|
|
1080
|
+
statusType = StatusTypes.SUBMITTED;
|
|
1081
|
+
}
|
|
1082
|
+
else {
|
|
1083
|
+
statusType = StatusTypes.UNKNOWN;
|
|
1084
|
+
}
|
|
1085
|
+
// Extract transaction hashes from intent order
|
|
1086
|
+
const txHash = intentOrder.txHash ?? '';
|
|
1087
|
+
// Check metadata for additional transaction hashes
|
|
1088
|
+
const metadataTxHashes = Array.isArray(intentOrder.metadata.txHashes)
|
|
1089
|
+
? intentOrder.metadata.txHashes
|
|
1090
|
+
: [];
|
|
1091
|
+
let allHashes;
|
|
1092
|
+
if (metadataTxHashes.length > 0) {
|
|
1093
|
+
allHashes = metadataTxHashes;
|
|
1094
|
+
}
|
|
1095
|
+
else if (txHash) {
|
|
1096
|
+
allHashes = [txHash];
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
allHashes = [];
|
|
1100
|
+
}
|
|
1101
|
+
const newStatus = {
|
|
1102
|
+
status: statusType,
|
|
1103
|
+
srcChain: {
|
|
1104
|
+
chainId: srcChainId,
|
|
1105
|
+
txHash: txHash ?? historyItem.status.srcChain.txHash ?? '',
|
|
1106
|
+
},
|
|
1107
|
+
};
|
|
1108
|
+
const newBridgeHistoryItem = {
|
|
1109
|
+
...historyItem,
|
|
1110
|
+
status: newStatus,
|
|
1111
|
+
completionTime: newStatus.status === StatusTypes.COMPLETE ||
|
|
1112
|
+
newStatus.status === StatusTypes.FAILED
|
|
1113
|
+
? Date.now()
|
|
1114
|
+
: undefined,
|
|
1115
|
+
attempts: undefined,
|
|
1116
|
+
srcTxHashes: allHashes.length > 0
|
|
1117
|
+
? Array.from(new Set([...(historyItem.srcTxHashes ?? []), ...allHashes]))
|
|
1118
|
+
: historyItem.srcTxHashes,
|
|
1119
|
+
};
|
|
1120
|
+
this.update((state) => {
|
|
1121
|
+
state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;
|
|
1122
|
+
});
|
|
1123
|
+
// Update the actual transaction in TransactionController to sync with intent status
|
|
1124
|
+
// Use the original transaction ID (not the intent: prefixed bridge history key)
|
|
1125
|
+
const originalTxId = historyItem.originalTransactionId ?? historyItem.txMetaId;
|
|
1126
|
+
if (originalTxId && !originalTxId.startsWith('intent:')) {
|
|
1127
|
+
try {
|
|
1128
|
+
const transactionStatus = mapIntentOrderStatusToTransactionStatus(intentOrder.status);
|
|
1129
|
+
// Merge with existing TransactionMeta to avoid wiping required fields
|
|
1130
|
+
const { transactions } = this.messenger.call('TransactionController:getState');
|
|
1131
|
+
const existingTxMeta = transactions.find((tx) => tx.id === originalTxId);
|
|
1132
|
+
if (existingTxMeta) {
|
|
1133
|
+
const updatedTxMeta = {
|
|
1134
|
+
...existingTxMeta,
|
|
1135
|
+
status: transactionStatus,
|
|
1136
|
+
...(txHash ? { hash: txHash } : {}),
|
|
1137
|
+
...(txHash
|
|
1138
|
+
? {
|
|
1139
|
+
txReceipt: {
|
|
1140
|
+
...existingTxMeta.txReceipt,
|
|
1141
|
+
transactionHash: txHash,
|
|
1142
|
+
status: (isComplete ? '0x1' : '0x0'),
|
|
1143
|
+
},
|
|
1144
|
+
}
|
|
1145
|
+
: {}),
|
|
1146
|
+
};
|
|
1147
|
+
__classPrivateFieldGet(this, _BridgeStatusController_updateTransactionFn, "f").call(this, updatedTxMeta, `BridgeStatusController - Intent order status updated: ${intentOrder.status}`);
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
console.warn('📝 [fetchIntentOrderStatus] Skipping update; transaction not found', { originalTxId, bridgeHistoryKey: bridgeTxMetaId });
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
catch (error) {
|
|
1154
|
+
/* c8 ignore start */
|
|
1155
|
+
console.error('📝 [fetchIntentOrderStatus] Failed to update transaction status', {
|
|
1156
|
+
originalTxId,
|
|
1157
|
+
bridgeHistoryKey: bridgeTxMetaId,
|
|
1158
|
+
error,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
/* c8 ignore stop */
|
|
1162
|
+
}
|
|
1163
|
+
const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
|
|
1164
|
+
const isFinal = newStatus.status === StatusTypes.COMPLETE ||
|
|
1165
|
+
newStatus.status === StatusTypes.FAILED;
|
|
1166
|
+
if (isFinal && pollingToken) {
|
|
1167
|
+
this.stopPollingByPollingToken(pollingToken);
|
|
1168
|
+
delete __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
|
|
1169
|
+
if (newStatus.status === StatusTypes.COMPLETE) {
|
|
1170
|
+
__classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Completed, bridgeTxMetaId);
|
|
1171
|
+
}
|
|
1172
|
+
else if (newStatus.status === StatusTypes.FAILED) {
|
|
1173
|
+
__classPrivateFieldGet(this, _BridgeStatusController_trackUnifiedSwapBridgeEvent, "f").call(this, UnifiedSwapBridgeEventName.Failed, bridgeTxMetaId);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
850
1176
|
};
|
|
851
1177
|
//# sourceMappingURL=bridge-status-controller.mjs.map
|