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