diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index c5c1a6c01a53..8958e454c431 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -107,6 +107,8 @@ const mockTransactionMetricsRequest = { getNetworkRpcUrl: jest.fn(), getFeatureFlags: jest.fn(), getPna25Acknowledged: jest.fn(), + getAddressSecurityAlertResponse: jest.fn(), + getSecurityAlertsEnabled: jest.fn(), } as TransactionMetricsRequest; describe('Transaction metrics', () => { @@ -184,6 +186,9 @@ describe('Transaction metrics', () => { account_type: undefined, // TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860 // eslint-disable-next-line @typescript-eslint/naming-convention + address_alert_response: 'not_applicable', + // TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860 + // eslint-disable-next-line @typescript-eslint/naming-convention api_method: MESSAGE_TYPE.ETH_SEND_TRANSACTION, // TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860 // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/app/scripts/lib/transaction/metrics.ts b/app/scripts/lib/transaction/metrics.ts index 8611d9095423..eaf114199125 100644 --- a/app/scripts/lib/transaction/metrics.ts +++ b/app/scripts/lib/transaction/metrics.ts @@ -63,6 +63,11 @@ import { shouldUseRedesignForTransactions } from '../../../../shared/lib/confirm import { getMaximumGasTotalInHexWei } from '../../../../shared/modules/gas.utils'; import { Numeric } from '../../../../shared/modules/Numeric'; import { extractRpcDomain } from '../util'; +import { + createCacheKey, + mapChainIdToSupportedEVMChain, + ResultType, +} from '../../../../shared/lib/trust-signals'; const log = createProjectLogger('transaction-metrics'); @@ -988,6 +993,11 @@ async function buildEventFragmentProperties({ hd_entropy_index: transactionMetricsRequest.getHDEntropyIndex(), }; + const addressAlertProperties = getAddressAlertMetricsProperties( + transactionMeta, + transactionMetricsRequest, + ); + let accountType; try { accountType = await transactionMetricsRequest.getAccountType( @@ -1029,6 +1039,7 @@ async function buildEventFragmentProperties({ ...smartTransactionMetricsProperties, ...swapAndSendMetricsProperties, ...hdEntropyProperties, + ...addressAlertProperties, // TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31973 // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -1437,3 +1448,45 @@ function addHashProperty( properties.transaction_hash = transactionMeta.hash; } } + +/** + * Returns what the address_alert_response metrics property should be set to + * + * @param transactionMeta - The transaction metadata + * @param transactionMetricsRequest - The transaction metrics request + * @returns ResultType or 'not_applicable' if address alert scanning cannot be performed: + * - Security alerts feature is disabled by the user + * - Transaction has no 'to' address + * - Chain is not supported by the Security Alerts API + */ +function getAddressAlertMetricsProperties( + transactionMeta: TransactionMeta, + transactionMetricsRequest: TransactionMetricsRequest, +): { address_alert_response?: ResultType | 'not_applicable' } { + const securityAlertsEnabled = + transactionMetricsRequest.getSecurityAlertsEnabled(); + if (!securityAlertsEnabled) { + return { address_alert_response: 'not_applicable' }; + } + + const { to } = transactionMeta.txParams; + if (typeof to !== 'string') { + return { address_alert_response: 'not_applicable' }; + } + + const { chainId } = transactionMeta; + const supportedEVMChain = mapChainIdToSupportedEVMChain(chainId); + if (!supportedEVMChain) { + return { address_alert_response: 'not_applicable' }; + } + + const cacheKey = createCacheKey(supportedEVMChain, to); + const cachedResponse = + transactionMetricsRequest.getAddressSecurityAlertResponse(cacheKey); + + if (cachedResponse) { + return { address_alert_response: cachedResponse.result_type }; + } + + return { address_alert_response: ResultType.Loading }; +} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 40c369a0f9aa..b20da03801d7 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -8218,6 +8218,14 @@ export default class MetamaskController extends EventEmitter { getPna25Acknowledged: () => { return this.appStateController?.state?.pna25Acknowledged; }, + getAddressSecurityAlertResponse: (cacheKey) => { + return this.appStateController?.getAddressSecurityAlertResponse( + cacheKey, + ); + }, + getSecurityAlertsEnabled: () => { + return this.preferencesController?.state?.securityAlertsEnabled; + }, }; const snapAndHardwareMessenger = new Messenger({ diff --git a/shared/modules/metametrics.test.ts b/shared/modules/metametrics.test.ts index fbca4380dfc9..fd66b49df8d6 100644 --- a/shared/modules/metametrics.test.ts +++ b/shared/modules/metametrics.test.ts @@ -49,6 +49,8 @@ const createTransactionMetricsRequest = (customProps = {}) => { getNetworkRpcUrl: jest.fn(), getFeatureFlags: jest.fn(), getPna25Acknowledged: jest.fn(), + getAddressSecurityAlertResponse: jest.fn(), + getSecurityAlertsEnabled: jest.fn(), ...customProps, } as TransactionMetricsRequest; }; diff --git a/shared/types/metametrics.ts b/shared/types/metametrics.ts index f4757f61bf72..0c321329e4f9 100644 --- a/shared/types/metametrics.ts +++ b/shared/types/metametrics.ts @@ -18,6 +18,7 @@ import type { HardwareKeyringType } from '../constants/hardware-wallets'; // eslint-disable-next-line import/no-restricted-paths import type { SnapAndHardwareMessenger } from '../../app/scripts/lib/snap-keyring/metrics'; import { EntryModalSourceEnum } from '../constants/subscriptions'; +import type { ScanAddressResponse } from '../lib/trust-signals'; export type TransactionMetricsRequest = { createEventFragment: ( @@ -74,6 +75,10 @@ export type TransactionMetricsRequest = { getNetworkRpcUrl: (chainId: Hex) => string; getFeatureFlags: () => Record; getPna25Acknowledged: () => boolean; + getAddressSecurityAlertResponse: ( + cacheKey: string, + ) => ScanAddressResponse | undefined; + getSecurityAlertsEnabled: () => boolean; }; export type TransactionEventPayload = {