diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 0dae1f432de..277816c07da 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -650,21 +650,11 @@ "count": 1 } }, - "packages/bridge-controller/src/utils/metrics/constants.ts": { - "@typescript-eslint/naming-convention": { - "count": 2 - } - }, "packages/bridge-controller/src/utils/metrics/properties.ts": { "@typescript-eslint/explicit-function-return-type": { "count": 5 } }, - "packages/bridge-controller/src/utils/metrics/types.ts": { - "@typescript-eslint/naming-convention": { - "count": 83 - } - }, "packages/bridge-controller/src/utils/quote-fees.ts": { "@typescript-eslint/explicit-function-return-type": { "count": 1 diff --git a/packages/bridge-controller/CHANGELOG.md b/packages/bridge-controller/CHANGELOG.md index 75bded7a9ec..cf3997a8c95 100644 --- a/packages/bridge-controller/CHANGELOG.md +++ b/packages/bridge-controller/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `HYPEREVM` network support ([#7787](https://github.com/MetaMask/core/pull/7787)) - Add `HYPEREVM` into constants `ALLOWED_BRIDGE_CHAIN_IDS`, `SWAPS_TOKEN_OBJECT` and `NETWORK_TO_NAME_MAP` +- Add `PollingStatusUpdated` to `UnifiedSwapBridgeEventName` enum and `PollingStatus` enum with `MaxPollingReached` and `ManuallyRestarted` values ([#7825](https://github.com/MetaMask/core/pull/7825)) ### Changed diff --git a/packages/bridge-controller/src/index.ts b/packages/bridge-controller/src/index.ts index 714397be2a2..666ab67908d 100644 --- a/packages/bridge-controller/src/index.ts +++ b/packages/bridge-controller/src/index.ts @@ -3,6 +3,7 @@ export { BridgeController } from './bridge-controller'; export { UnifiedSwapBridgeEventName, UNIFIED_SWAP_BRIDGE_EVENT_CATEGORY, + PollingStatus, } from './utils/metrics/constants'; export type { diff --git a/packages/bridge-controller/src/utils/metrics/constants.ts b/packages/bridge-controller/src/utils/metrics/constants.ts index bf5da4454f3..4b4d94e9461 100644 --- a/packages/bridge-controller/src/utils/metrics/constants.ts +++ b/packages/bridge-controller/src/utils/metrics/constants.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ export const UNIFIED_SWAP_BRIDGE_EVENT_CATEGORY = 'Unified SwapBridge'; /** @@ -20,6 +21,12 @@ export enum UnifiedSwapBridgeEventName { AssetDetailTooltipClicked = `${UNIFIED_SWAP_BRIDGE_EVENT_CATEGORY} Asset Detail Tooltip Clicked`, QuotesValidationFailed = `${UNIFIED_SWAP_BRIDGE_EVENT_CATEGORY} Quotes Failed Validation`, StatusValidationFailed = `${UNIFIED_SWAP_BRIDGE_EVENT_CATEGORY} Status Failed Validation`, + PollingStatusUpdated = `${UNIFIED_SWAP_BRIDGE_EVENT_CATEGORY} Polling Status Updated`, +} + +export enum PollingStatus { + MaxPollingReached = 'max_polling_reached', + ManuallyRestarted = 'manually_restarted', } export enum AbortReason { diff --git a/packages/bridge-controller/src/utils/metrics/types.ts b/packages/bridge-controller/src/utils/metrics/types.ts index fe6c7a0ef40..b78dd35c520 100644 --- a/packages/bridge-controller/src/utils/metrics/types.ts +++ b/packages/bridge-controller/src/utils/metrics/types.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import type { CaipAssetType, CaipChainId } from '@metamask/utils'; import type { @@ -5,6 +6,7 @@ import type { MetaMetricsSwapsEventSource, MetricsActionType, MetricsSwapType, + PollingStatus, } from './constants'; import type { SortOrder, StatusTypes } from '../../types'; @@ -212,6 +214,20 @@ export type RequiredEventContextFromClient = { [UnifiedSwapBridgeEventName.StatusValidationFailed]: { failures: string[]; }; + [UnifiedSwapBridgeEventName.PollingStatusUpdated]: TradeData & + Pick & + Omit & + Pick< + RequestParams, + | 'token_symbol_source' + | 'token_symbol_destination' + | 'chain_id_source' + | 'chain_id_destination' + > & { + action_type: MetricsActionType; + polling_status: PollingStatus; + retry_attempts: number; + }; }; /** @@ -268,6 +284,7 @@ export type EventPropertiesFromControllerState = { [UnifiedSwapBridgeEventName.StatusValidationFailed]: RequestParams & { refresh_count: number; }; + [UnifiedSwapBridgeEventName.PollingStatusUpdated]: null; }; /** diff --git a/packages/bridge-status-controller/CHANGELOG.md b/packages/bridge-status-controller/CHANGELOG.md index 3a139096178..b3c16179183 100644 --- a/packages/bridge-status-controller/CHANGELOG.md +++ b/packages/bridge-status-controller/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `Unified SwapBridge Polling Status Updated` metrics event with `status` property (`max_polling_reached` or `manually_restarted`), emitted when polling stops due to max attempts or is manually restarted ([#7825](https://github.com/MetaMask/core/pull/7825)) + ### Changed - Bump `@metamask/transaction-controller` from `^62.11.0` to `^62.12.0` ([#7775](https://github.com/MetaMask/core/pull/7775)) diff --git a/packages/bridge-status-controller/src/bridge-status-controller.ts b/packages/bridge-status-controller/src/bridge-status-controller.ts index 7383d6d963e..bfe50c56232 100644 --- a/packages/bridge-status-controller/src/bridge-status-controller.ts +++ b/packages/bridge-status-controller/src/bridge-status-controller.ts @@ -21,6 +21,7 @@ import { isBitcoinTrade, isTronTrade, AbortReason, + PollingStatus, } from '@metamask/bridge-controller'; import type { TraceCallback } from '@metamask/controller-utils'; import { toHex } from '@metamask/controller-utils'; @@ -379,6 +380,9 @@ export class BridgeStatusController extends StaticIntervalPollingController { if (targetTxMetaId) { @@ -400,6 +404,38 @@ export class BridgeStatusController extends StaticIntervalPollingController= MAX_ATTEMPTS && pollingToken) { this.stopPollingByPollingToken(pollingToken); delete this.#pollingTokensByTxMetaId[bridgeTxMetaId]; + + // Track max polling reached event + const historyItem = this.state.txHistory[bridgeTxMetaId]; + if (historyItem && !historyItem.featureId) { + const selectedAccount = this.messenger.call( + 'AccountsController:getAccountByAddress', + historyItem.account, + ); + const requestParams = getRequestParamFromHistory(historyItem); + const requestMetadata = getRequestMetadataFromHistory( + historyItem, + selectedAccount, + ); + const { security_warnings: _, ...metadataWithoutWarnings } = + requestMetadata; + + this.#trackUnifiedSwapBridgeEvent( + UnifiedSwapBridgeEventName.PollingStatusUpdated, + bridgeTxMetaId, + { + ...getTradeDataFromHistory(historyItem), + ...getPriceImpactFromQuote(historyItem.quote), + ...metadataWithoutWarnings, + chain_id_source: requestParams.chain_id_source, + chain_id_destination: requestParams.chain_id_destination, + token_symbol_source: requestParams.token_symbol_source, + token_symbol_destination: requestParams.token_symbol_destination, + action_type: MetricsActionType.SWAPBRIDGE_V1, + polling_status: PollingStatus.MaxPollingReached, + retry_attempts: newAttempts.counter, + }, + ); + } } // Update the attempts counter @@ -1915,7 +1984,8 @@ export class BridgeStatusController extends StaticIntervalPollingController( eventName: EventName, txMetaId?: string,