@metamask-previews/bridge-controller 79.2.0-preview-f7d67b054 → 79.2.0-preview-3c77cf4

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 CHANGED
@@ -7,10 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ### Added
11
-
12
- - Add Sentry quote-fetch and provider first-result performance traces ([#9899](https://github.com/MetaMask/core/pull/9899))
13
-
14
10
  ### Changed
15
11
 
16
12
  - Bump `@metamask/assets-controller` from `^13.1.2` to `^13.1.4` ([#9873](https://github.com/MetaMask/core/pull/9873), [#9886](https://github.com/MetaMask/core/pull/9886))
@@ -19,7 +19,6 @@ const contracts_1 = require("@ethersproject/contracts");
19
19
  const providers_1 = require("@ethersproject/providers");
20
20
  const metamask_eth_abis_1 = require("@metamask/metamask-eth-abis");
21
21
  const polling_controller_1 = require("@metamask/polling-controller");
22
- const uuid_1 = require("uuid");
23
22
  const quote_response_v1_to_v2_js_1 = require("./coercers/quote-response-v1-to-v2.cjs");
24
23
  const bridge_js_1 = require("./constants/bridge.cjs");
25
24
  const chains_js_1 = require("./constants/chains.cjs");
@@ -130,18 +129,6 @@ const metadata = {
130
129
  usedInUi: true,
131
130
  },
132
131
  };
133
- const QUOTE_ABORT_REASONS = new Set(Object.values(constants_js_1.AbortReason));
134
- const isExpectedQuoteAbort = (error, signal) => {
135
- if (signal?.aborted) {
136
- return true;
137
- }
138
- if (QUOTE_ABORT_REASONS.has(String(error))) {
139
- return true;
140
- }
141
- const errorText = error instanceof Error ? `${error.name} ${error.message}` : String(error);
142
- return (errorText.includes('AbortError') ||
143
- errorText.includes('FetchRequestCanceledException'));
144
- };
145
132
  const MESSENGER_EXPOSED_METHODS = [
146
133
  'updateBridgeQuoteRequestParams',
147
134
  'fetchQuotes',
@@ -517,9 +504,6 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
517
504
  __classPrivateFieldGet(this, _BridgeController_abortController, "f")?.abort(constants_js_1.AbortReason.NewQuoteRequest);
518
505
  __classPrivateFieldGet(this, _BridgeController_batchSellTradesAbortController, "f")?.abort(constants_js_1.AbortReason.NewQuoteRequest);
519
506
  __classPrivateFieldSet(this, _BridgeController_abortController, new AbortController(), "f");
520
- const quoteTraceStartTime = Date.now();
521
- const quoteTraceRequestId = (0, uuid_1.v4)();
522
- const quoteAbortSignal = __classPrivateFieldGet(this, _BridgeController_abortController, "f").signal;
523
507
  __classPrivateFieldGet(this, _BridgeController_fetchAssetExchangeRates, "f").call(this, quoteRequests).catch((error) => console.warn('Failed to fetch asset exchange rates', error));
524
508
  this.trackUnifiedSwapBridgeEvent(constants_js_1.UnifiedSwapBridgeEventName.QuotesRequested, context);
525
509
  const { sse, maxRefreshCount } = (0, feature_flags_js_1.getBridgeFeatureFlags)(this.messenger);
@@ -540,84 +524,43 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
540
524
  }
541
525
  });
542
526
  const jwt = await __classPrivateFieldGet(this, _BridgeController_getJwt, "f").call(this);
543
- const [firstQuoteRequest] = quoteRequests;
544
- let traceResult = 'error';
545
- let traceName = traces_js_1.TraceName.BatchSellQuotesFetched;
546
- if (!isBatchSellRequest) {
547
- traceName = (0, bridge_js_2.isCrossChain)(firstQuoteRequest.srcChainId, firstQuoteRequest.destChainId)
527
+ try {
528
+ const [firstQuoteRequest] = quoteRequests;
529
+ const unifiedSwapTraceName = (0, bridge_js_2.isCrossChain)(firstQuoteRequest.srcChainId, firstQuoteRequest.destChainId)
548
530
  ? traces_js_1.TraceName.BridgeQuotesFetched
549
531
  : traces_js_1.TraceName.SwapQuotesFetched;
550
- }
551
- const tracedProviders = new Set();
552
- const traceWithoutImpact = async (request) => {
553
- try {
554
- await __classPrivateFieldGet(this, _BridgeController_trace, "f").call(this, request, () => undefined);
555
- }
556
- catch {
557
- // Telemetry failures must not affect quote fetching or state updates.
558
- }
559
- };
560
- const traceProviderFirstResult = (providerData) => {
561
- const provider = (0, properties_js_1.formatProviderLabel)(providerData);
562
- if (isBatchSellRequest || tracedProviders.has(provider)) {
563
- return;
564
- }
565
- tracedProviders.add(provider);
566
- // Provider telemetry must not delay quote processing.
567
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
568
- traceWithoutImpact({
569
- name: traces_js_1.TraceName.QuoteProviderFirstResult,
570
- startTime: quoteTraceStartTime,
532
+ await __classPrivateFieldGet(this, _BridgeController_trace, "f").call(this, {
533
+ name: isBatchSellRequest
534
+ ? traces_js_1.TraceName.BatchSellQuotesFetched
535
+ : unifiedSwapTraceName,
571
536
  data: {
572
- provider,
573
- feature_id: context.feature_id,
574
- request_id: quoteTraceRequestId,
575
- swap_type: (0, properties_js_1.getSwapType)(firstQuoteRequest.srcChainId, firstQuoteRequest.destChainId),
576
537
  srcChainId: (0, caip_formatters_js_1.formatChainIdToCaip)(firstQuoteRequest.srcChainId),
577
538
  destChainId: (0, caip_formatters_js_1.formatChainIdToCaip)(firstQuoteRequest.destChainId),
578
- result: 'success',
579
539
  },
580
- });
581
- };
582
- try {
583
- const selectedAccount = __classPrivateFieldGet(this, _BridgeController_instances, "m", _BridgeController_getMultichainSelectedAccount).call(this, firstQuoteRequest.walletAddress);
584
- // This call is not awaited to prevent blocking quote fetching if the snap takes too long to respond
585
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
586
- __classPrivateFieldGet(this, _BridgeController_setMinimumBalanceForRentExemptionInLamports, "f").call(this, firstQuoteRequest.srcChainId, selectedAccount?.metadata?.snap?.id);
587
- // Use SSE if enabled and return early
588
- if (shouldStream || isBatchSellRequest) {
589
- const quoteCount = await __classPrivateFieldGet(this, _BridgeController_handleQuoteStreaming, "f").call(this, {
590
- quoteRequests,
591
- featureId: context.feature_id,
592
- jwt,
593
- selectedAccount,
594
- signal: quoteAbortSignal,
595
- traceProviderFirstResult,
596
- });
597
- if (quoteAbortSignal.aborted) {
598
- traceResult = 'cancelled';
540
+ }, async () => {
541
+ const selectedAccount = __classPrivateFieldGet(this, _BridgeController_instances, "m", _BridgeController_getMultichainSelectedAccount).call(this, firstQuoteRequest.walletAddress);
542
+ // This call is not awaited to prevent blocking quote fetching if the snap takes too long to respond
543
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
544
+ __classPrivateFieldGet(this, _BridgeController_setMinimumBalanceForRentExemptionInLamports, "f").call(this, firstQuoteRequest.srcChainId, selectedAccount?.metadata?.snap?.id);
545
+ // Use SSE if enabled and return early
546
+ if (shouldStream || isBatchSellRequest) {
547
+ await __classPrivateFieldGet(this, _BridgeController_handleQuoteStreaming, "f").call(this, quoteRequests, context.feature_id, jwt, selectedAccount);
599
548
  return;
600
549
  }
601
- traceResult = quoteCount > 0 ? 'success' : 'no_quotes';
602
- }
603
- else {
604
550
  // Otherwise use regular fetch
605
- const quotes = await this.fetchQuotes(firstQuoteRequest, context.feature_id, quoteAbortSignal);
606
- for (const quote of quotes) {
607
- traceProviderFirstResult(quote.quote);
608
- }
551
+ const quotes = await this.fetchQuotes(firstQuoteRequest, context.feature_id, __classPrivateFieldGet(this, _BridgeController_abortController, "f")?.signal);
609
552
  this.update((state) => {
610
553
  // Set the initial load time if this is the first fetch
611
554
  if (state.quotesRefreshCount ===
612
555
  bridge_js_1.DEFAULT_BRIDGE_CONTROLLER_STATE.quotesRefreshCount &&
613
556
  __classPrivateFieldGet(this, _BridgeController_quotesFirstFetched, "f")) {
614
- state.quotesInitialLoadTime = Date.now() - __classPrivateFieldGet(this, _BridgeController_quotesFirstFetched, "f");
557
+ state.quotesInitialLoadTime =
558
+ Date.now() - __classPrivateFieldGet(this, _BridgeController_quotesFirstFetched, "f");
615
559
  }
616
560
  state.quotes = quotes.map(quote_response_v1_to_v2_js_1.toQuoteResponseV2);
617
561
  state.quotesLoadingStatus = types_js_1.RequestStatus.FETCHED;
618
562
  });
619
- traceResult = quotes.length > 0 ? 'success' : 'no_quotes';
620
- }
563
+ });
621
564
  }
622
565
  catch (error) {
623
566
  // Reset the quotes list if the fetch fails to avoid showing stale quotes
@@ -625,8 +568,14 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
625
568
  state.quotes = bridge_js_1.DEFAULT_BRIDGE_CONTROLLER_STATE.quotes;
626
569
  });
627
570
  // Ignore abort errors
628
- if (isExpectedQuoteAbort(error, quoteAbortSignal)) {
629
- traceResult = 'cancelled';
571
+ if (error.toString().includes('AbortError') ||
572
+ error.toString().includes('FetchRequestCanceledException') ||
573
+ [
574
+ constants_js_1.AbortReason.ResetState,
575
+ constants_js_1.AbortReason.NewQuoteRequest,
576
+ constants_js_1.AbortReason.QuoteRequestUpdated,
577
+ constants_js_1.AbortReason.TransactionSubmitted,
578
+ ].includes(error)) {
630
579
  // Exit the function early to prevent other state updates
631
580
  return;
632
581
  }
@@ -651,21 +600,6 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
651
600
  this.trackUnifiedSwapBridgeEvent(constants_js_1.UnifiedSwapBridgeEventName.QuotesError, context);
652
601
  console.log(`Failed to ${shouldStream ? 'stream' : 'fetch'} bridge quotes`, error);
653
602
  }
654
- finally {
655
- await traceWithoutImpact({
656
- name: traceName,
657
- startTime: quoteTraceStartTime,
658
- data: {
659
- srcChainId: (0, caip_formatters_js_1.formatChainIdToCaip)(firstQuoteRequest.srcChainId),
660
- destChainId: (0, caip_formatters_js_1.formatChainIdToCaip)(firstQuoteRequest.destChainId),
661
- ...(!isBatchSellRequest && {
662
- request_id: quoteTraceRequestId,
663
- feature_id: context.feature_id,
664
- result: traceResult,
665
- }),
666
- },
667
- });
668
- }
669
603
  // Update refresh count after fetching, validation and fee calculation have completed
670
604
  this.update((state) => {
671
605
  state.quotesRefreshCount += 1;
@@ -680,7 +614,7 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
680
614
  this.stopAllPolling();
681
615
  }
682
616
  });
683
- _BridgeController_handleQuoteStreaming.set(this, async ({ quoteRequests, featureId, jwt, selectedAccount, signal, traceProviderFirstResult, }) => {
617
+ _BridgeController_handleQuoteStreaming.set(this, async (quoteRequests, featureId, jwt, selectedAccount) => {
684
618
  /**
685
619
  * Tracks the number of valid quotes received from the current stream, which is used
686
620
  * to determine when to clear the quotes list and set the initial load time
@@ -691,14 +625,13 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
691
625
  * before setting quotesLoadingStatus to FETCHED
692
626
  */
693
627
  const pendingFeeAppendPromises = new Set();
694
- await (0, fetch_js_1.fetchBridgeQuoteStream)(__classPrivateFieldGet(this, _BridgeController_fetchFn, "f"), quoteRequests, signal, featureId, __classPrivateFieldGet(this, _BridgeController_clientId, "f"), jwt, __classPrivateFieldGet(this, _BridgeController_config, "f").customBridgeApiBaseUrl ?? bridge_js_1.BRIDGE_PROD_API_BASE_URL, {
628
+ await (0, fetch_js_1.fetchBridgeQuoteStream)(__classPrivateFieldGet(this, _BridgeController_fetchFn, "f"), quoteRequests, __classPrivateFieldGet(this, _BridgeController_abortController, "f")?.signal, featureId, __classPrivateFieldGet(this, _BridgeController_clientId, "f"), jwt, __classPrivateFieldGet(this, _BridgeController_config, "f").customBridgeApiBaseUrl ?? bridge_js_1.BRIDGE_PROD_API_BASE_URL, {
695
629
  onQuoteValidationFailure: (validationFailures) => __classPrivateFieldGet(this, _BridgeController_trackQuoteValidationFailures, "f").call(this, validationFailures, featureId),
696
630
  onValidQuoteReceived: async (quote) => {
697
631
  const feeAppendPromise = (async () => {
698
632
  const quotesWithFees = await (0, quote_fees_js_1.appendFeesToQuotes)(quote.chainId, [quote], this.messenger, __classPrivateFieldGet(this, _BridgeController_getLayer1GasFee, "f"), selectedAccount);
699
633
  if (quotesWithFees.length > 0) {
700
634
  validQuotesCounter += 1;
701
- traceProviderFirstResult(quote.quote);
702
635
  }
703
636
  this.update((state) => {
704
637
  // Clear previous quotes and quotes load time when first quote in the current
@@ -758,7 +691,6 @@ class BridgeController extends (0, polling_controller_1.StaticIntervalPollingCon
758
691
  });
759
692
  },
760
693
  }, __classPrivateFieldGet(this, _BridgeController_clientVersion, "f"));
761
- return validQuotesCounter;
762
694
  });
763
695
  _BridgeController_setMinimumBalanceForRentExemptionInLamports.set(this, async (srcChainId, snapId) => {
764
696
  if (!(0, bridge_js_2.isSolanaChainId)(srcChainId) || !snapId) {