From bccc48966e369f048475803fdfbd1a655a0a2232 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:55:07 -0800 Subject: [PATCH 01/17] refactor: separate selector from hook useTypedSignSimulationEnabled - to use with react class components --- .../hooks/useTypedSignSimulationEnabled.ts | 62 ++----------------- .../confirmations/utils/signatureDecoding.ts | 33 ++++++++++ app/selectors/signatureController.ts | 33 +++++++++- 3 files changed, 69 insertions(+), 59 deletions(-) create mode 100644 app/components/Views/confirmations/utils/signatureDecoding.ts diff --git a/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts b/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts index 0553f8fcae2..300fb11e7d5 100644 --- a/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts +++ b/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts @@ -1,66 +1,12 @@ import { useSelector } from 'react-redux'; -import { SignTypedDataVersion } from '@metamask/eth-sig-util'; -import { MessageParamsTyped, SignatureRequest, SignatureRequestType } from '@metamask/signature-controller'; -import { selectUseTransactionSimulations } from '../../../../selectors/preferencesController'; -import { isRecognizedPermit, parseTypedDataMessage } from '../utils/signature'; +import { selectTypedSignSimulationEnabled } from '../../../../selectors/signatureController'; +import { RootState } from '../../../UI/BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal.test'; import { useSignatureRequest } from './useSignatureRequest'; -const NON_PERMIT_SUPPORTED_TYPES_SIGNS = [ - { - domainName: 'Seaport', - primaryTypeList: ['BulkOrder'], - versionList: ['1.4', '1.5', '1.6'], - }, - { - domainName: 'Seaport', - primaryTypeList: ['OrderComponents'], - }, -]; - -const isNonPermitSupportedByDecodingAPI = ( - signatureRequest: SignatureRequest, -) => { - const data = signatureRequest.messageParams?.data as string; - if (!data) { return false; } - - const { - domain: { name, version }, - primaryType, - } = parseTypedDataMessage(data); - - return NON_PERMIT_SUPPORTED_TYPES_SIGNS.some( - ({ domainName, primaryTypeList, versionList }) => - name === domainName && - primaryTypeList.includes(primaryType) && - (!versionList || versionList.includes(version)), - ); -}; - export function useTypedSignSimulationEnabled() { const signatureRequest = useSignatureRequest(); - const useTransactionSimulations = useSelector( - selectUseTransactionSimulations, - ); - - if (!signatureRequest) { - return undefined; - } - - const requestType = signatureRequest.type; - const signatureMethod = (signatureRequest.messageParams as MessageParamsTyped)?.version; - - const isTypedSignV3V4 = requestType === SignatureRequestType.TypedSign && ( - signatureMethod === SignTypedDataVersion.V3 || - signatureMethod === SignTypedDataVersion.V4 - ); - const isPermit = isRecognizedPermit(signatureRequest); - - const nonPermitSupportedByDecodingAPI: boolean = - isTypedSignV3V4 && isNonPermitSupportedByDecodingAPI(signatureRequest); - return ( - useTransactionSimulations && - isTypedSignV3V4 && - (isPermit || nonPermitSupportedByDecodingAPI) + return useSelector((state: RootState) => + selectTypedSignSimulationEnabled(state, signatureRequest?.id as string) ); } diff --git a/app/components/Views/confirmations/utils/signatureDecoding.ts b/app/components/Views/confirmations/utils/signatureDecoding.ts new file mode 100644 index 00000000000..9adc4b8dd8b --- /dev/null +++ b/app/components/Views/confirmations/utils/signatureDecoding.ts @@ -0,0 +1,33 @@ +import { SignatureRequest } from '@metamask/signature-controller'; +import { parseTypedDataMessage } from './signature'; + +const NON_PERMIT_SUPPORTED_TYPES_SIGNS = [ + { + domainName: 'Seaport', + primaryTypeList: ['BulkOrder'], + versionList: ['1.4', '1.5', '1.6'], + }, + { + domainName: 'Seaport', + primaryTypeList: ['OrderComponents'], + }, +]; + +export const isNonPermitSupportedByDecodingAPI = ( + signatureRequest: SignatureRequest, +) => { + const data = signatureRequest.messageParams?.data as string; + if (!data) { return false; } + + const { + domain: { name, version }, + primaryType, + } = parseTypedDataMessage(data); + + return NON_PERMIT_SUPPORTED_TYPES_SIGNS.some( + ({ domainName, primaryTypeList, versionList }) => + name === domainName && + primaryTypeList.includes(primaryType) && + (!versionList || versionList.includes(version)), + ); +}; diff --git a/app/selectors/signatureController.ts b/app/selectors/signatureController.ts index 8d9ba0f9ead..1e83dca1903 100644 --- a/app/selectors/signatureController.ts +++ b/app/selectors/signatureController.ts @@ -1,4 +1,8 @@ -import { SignatureRequest } from '@metamask/signature-controller'; +import { SignTypedDataVersion } from '@metamask/eth-sig-util'; +import { MessageParamsTyped, SignatureRequest, SignatureRequestType } from '@metamask/signature-controller'; +import { selectUseTransactionSimulations } from './preferencesController'; +import { isRecognizedPermit } from '../components/Views/confirmations/utils/signature'; +import { isNonPermitSupportedByDecodingAPI } from '../components/Views/confirmations/utils/signatureDecoding'; import { RootState } from '../reducers'; import { createDeepEqualSelector } from './util'; @@ -16,3 +20,30 @@ export const selectSignatureRequestById = createDeepEqualSelector( (signatureRequests, id) => signatureRequests[id] as SignatureRequest | undefined, ); + +export const selectTypedSignSimulationEnabled = createDeepEqualSelector( + [selectSignatureRequestById, selectUseTransactionSimulations], + (signatureRequest, useTransactionSimulations) => { + if (!signatureRequest) { + return undefined; + } + + const requestType = signatureRequest.type; + const signatureMethod = (signatureRequest.messageParams as MessageParamsTyped)?.version; + + const isTypedSignV3V4 = requestType === SignatureRequestType.TypedSign && ( + signatureMethod === SignTypedDataVersion.V3 || + signatureMethod === SignTypedDataVersion.V4 + ); + const isPermit = isRecognizedPermit(signatureRequest); + + const nonPermitSupportedByDecodingAPI: boolean = + isTypedSignV3V4 && isNonPermitSupportedByDecodingAPI(signatureRequest); + + return ( + useTransactionSimulations && + isTypedSignV3V4 && + (isPermit || nonPermitSupportedByDecodingAPI) + ); + } +); From c36e23ab721bb4a9696c6338c04944ada4360814 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:56:45 -0800 Subject: [PATCH 02/17] feat: add signature decoding metrics --- .../SignatureBlockaidBanner.tsx | 23 ++++++------ .../components/SignatureRequest/index.js | 36 ++++++++++++++++--- .../components/TypedSign/index.js | 8 ++++- .../hooks/useSignatureMetrics.ts | 22 +++++++----- .../confirmations/utils/signatureMetrics.ts | 34 ++++++++++++++++++ 5 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 app/components/Views/confirmations/utils/signatureMetrics.ts diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx index 198f2290376..56fe7001f16 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx @@ -6,40 +6,43 @@ import { useStyles } from '../../../../../../component-library/hooks'; import { useMetrics } from '../../../../../hooks/useMetrics'; import BlockaidBanner from '../../../components/BlockaidBanner/BlockaidBanner'; import useApprovalRequest from '../../../hooks/useApprovalRequest'; +import { useSignatureRequest } from '../../../hooks/useSignatureRequest'; +import { getSignatureDecodingEventProps } from '../../../utils/signatureMetrics'; import styleSheet from './SignatureBlockaidBanner.styles'; +import { useTypedSignSimulationEnabled } from '../../../hooks/useTypedSignSimulationEnabled'; const SignatureBlockaidBanner = () => { const { approvalRequest } = useApprovalRequest(); + const signatureRequest = useSignatureRequest(); + const isSimulationEnabled = useTypedSignSimulationEnabled(); const { trackEvent, createEventBuilder } = useMetrics(); const { styles } = useStyles(styleSheet, {}); const { type, - requestData: { from: fromAddress }, - } = approvalRequest ?? { - requestData: {}, + messageParams: { from: fromAddress }, + } = signatureRequest ?? { + messageParams: {}, }; const onContactUsClicked = useCallback(() => { - const analyticsParams = { + const eventProps = { ...getAnalyticsParams( { from: fromAddress, }, type, ), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), external_link_clicked: 'security_alert_support_link', }; + trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_REQUESTED) - .addProperties(analyticsParams) + .addProperties(eventProps) .build(), ); - }, [trackEvent, createEventBuilder, type, fromAddress]); - - if (!approvalRequest?.requestData?.securityAlertResponse) { - return null; - } + }, [trackEvent, createEventBuilder, signatureRequest, type, fromAddress]); return ( { try { @@ -143,6 +146,14 @@ class SignatureRequest extends PureComponent { * Object containing current page title and url */ currentPageInformation: PropTypes.object, + /** + * Whether signature simulation with decoding API is enabled + */ + isSimulationEnabled: PropTypes.bool, + /** + * Signature request object + */ + signatureRequest: PropTypes.object, /** * String representing signature type */ @@ -218,7 +229,18 @@ class SignatureRequest extends PureComponent { }; componentDidMount = () => { - const { currentPageInformation, type, fromAddress } = this.props; + const { currentPageInformation, isSimulationEnabled, type, fromAddress, signatureRequest } = this.props; + + const eventProps = { + ...getAnalyticsParams( + { + currentPageInformation, + from: fromAddress, + }, + type, + ), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), + }; this.props.metrics.trackEvent( this.props.metrics @@ -302,20 +324,22 @@ class SignatureRequest extends PureComponent { }; onContactUsClicked = () => { - const { fromAddress, type } = this.props; - const analyticsParams = { + const { fromAddress, isSimulationEnabled, type, signatureRequest } = this.props; + + const eventProps = { ...getAnalyticsParams( { from: fromAddress, }, type, ), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), external_link_clicked: 'security_alert_support_link', }; this.props.metrics.trackEvent( this.props.metrics .createEventBuilder(MetaMetricsEvents.SIGNATURE_REQUESTED) - .addProperties(analyticsParams) + .addProperties(eventProps) .build(), ); }; @@ -399,8 +423,10 @@ class SignatureRequest extends PureComponent { } const mapStateToProps = (state) => ({ - selectedAddress: selectSelectedInternalAccountFormattedAddress(state), + isSimulationEnabled: selectTypedSignSimulationEnabled(state, Object.values(selectPendingApprovals(state) || {})[0].id), securityAlertResponse: state.signatureRequest.securityAlertResponse, + selectedAddress: selectSelectedInternalAccountFormattedAddress(state), + signatureRequest: Object.values(selectPendingApprovals(state) || {})[0], }); SignatureRequest.contextType = ThemeContext; diff --git a/app/components/Views/confirmations/components/TypedSign/index.js b/app/components/Views/confirmations/components/TypedSign/index.js index 04953a7865e..c56dc4c52bf 100644 --- a/app/components/Views/confirmations/components/TypedSign/index.js +++ b/app/components/Views/confirmations/components/TypedSign/index.js @@ -15,6 +15,7 @@ import { sanitizeString, } from '../../../../../util/string'; +import { getSignatureDecodingEventProps } from '../../utils/signatureMetrics'; import { addSignatureErrorListener, getAnalyticsParams, @@ -114,11 +115,16 @@ class TypedSign extends PureComponent { metrics, } = this.props; + const eventProps = { + ...getAnalyticsParams(messageParams, 'typed_sign'), + ...getSignatureDecodingEventProps(messageParams), + }; + metrics.trackEvent( MetricsEventBuilder.createEventBuilder( MetaMetricsEvents.SIGNATURE_REQUESTED, ) - .addProperties(getAnalyticsParams(messageParams, 'typed_sign')) + .addProperties(eventProps) .build(), ); addSignatureErrorListener(metamaskId, this.onSignatureError); diff --git a/app/components/Views/confirmations/hooks/useSignatureMetrics.ts b/app/components/Views/confirmations/hooks/useSignatureMetrics.ts index ec345a42083..2ad614affad 100644 --- a/app/components/Views/confirmations/hooks/useSignatureMetrics.ts +++ b/app/components/Views/confirmations/hooks/useSignatureMetrics.ts @@ -10,7 +10,9 @@ import { getBlockaidMetricsParams } from '../../../../util/blockaid'; import { SecurityAlertResponse } from '../components/BlockaidBanner/BlockaidBanner.types'; import { getHostFromUrl } from '../utils/generic'; import { isSignatureRequest } from '../utils/confirm'; +import { getSignatureDecodingEventProps } from '../utils/signatureMetrics'; import { useSignatureRequest } from './useSignatureRequest'; +import { useTypedSignSimulationEnabled } from './useTypedSignSimulationEnabled'; interface MessageParamsType { meta: Record; @@ -42,6 +44,7 @@ const getAnalyticsParams = ( export const useSignatureMetrics = () => { const signatureRequest = useSignatureRequest(); + const isSimulationEnabled = useTypedSignSimulationEnabled(); const { chainId, messageParams, type } = signatureRequest ?? {}; @@ -53,19 +56,22 @@ export const useSignatureMetrics = () => { return; } + const eventProps = { + ...getAnalyticsParams( + messageParams as unknown as MessageParamsType, + type, + chainId, + ), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), + }; + MetaMetrics.getInstance().trackEvent( MetricsEventBuilder.createEventBuilder(event) - .addProperties( - getAnalyticsParams( - messageParams as unknown as MessageParamsType, - type, - chainId, - ), - ) + .addProperties(eventProps) .build(), ); }, - [chainId, messageParams, type], + [chainId, isSimulationEnabled, messageParams, type, signatureRequest], ); useEffect(() => { diff --git a/app/components/Views/confirmations/utils/signatureMetrics.ts b/app/components/Views/confirmations/utils/signatureMetrics.ts new file mode 100644 index 00000000000..63ee22647f1 --- /dev/null +++ b/app/components/Views/confirmations/utils/signatureMetrics.ts @@ -0,0 +1,34 @@ +import { DecodingDataStateChange, SignatureRequest } from '@metamask/signature-controller'; + +enum DecodingResponseType { + Change = 'CHANGE', + NoChange = 'NO_CHANGE', + Loading = 'decoding_in_progress', +} + +export const getSignatureDecodingEventProps = (signatureRequest?: SignatureRequest, isDecodingAPIEnabled: boolean = false) => { + const { decodingData, decodingLoading } = signatureRequest || {}; + + if (!isDecodingAPIEnabled || !decodingData) { + return {}; + } + + const { stateChanges, error } = decodingData; + + const changeTypes = (stateChanges ?? []).map( + (change: DecodingDataStateChange) => change.changeType, + ); + + const responseType = error?.type ?? + (changeTypes.length + ? DecodingResponseType.Change + : DecodingResponseType.NoChange); + + return { + decoding_change_types: changeTypes, + decoding_description: decodingData?.error?.message ?? null, + decoding_response: decodingLoading + ? DecodingResponseType.Loading + : responseType, + }; +}; From b090900386ed858df610b0fa7f0099540cc29bed Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:11:01 -0800 Subject: [PATCH 03/17] test: create signature metrics utils test --- .../utils/signatureMetrics.test.ts | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 app/components/Views/confirmations/utils/signatureMetrics.test.ts diff --git a/app/components/Views/confirmations/utils/signatureMetrics.test.ts b/app/components/Views/confirmations/utils/signatureMetrics.test.ts new file mode 100644 index 00000000000..8df940d5d8c --- /dev/null +++ b/app/components/Views/confirmations/utils/signatureMetrics.test.ts @@ -0,0 +1,121 @@ +import { Hex } from '@metamask/utils'; +import { getSignatureDecodingEventProps } from './signatureMetrics'; +import { DecodingDataChangeType, SignatureRequest, SignatureRequestStatus, SignatureRequestType } from '@metamask/signature-controller'; + +const mockSignatureRequest = { + id: 'fb2029e1-b0ab-11ef-9227-05a11087c334', + chainId: '0x1' as Hex, + type: SignatureRequestType.TypedSign, + messageParams: { + data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x935e73edb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + version: 'V4', + requestId: 14, + origin: 'https://metamask.github.io', + metamaskId: 'fb2029e0-b0ab-11ef-9227-05a11087c334', + }, + networkClientId: '1', + status: SignatureRequestStatus.Unapproved, + time: 1733143817088 +} satisfies SignatureRequest; + +describe('signatureMetrics', () => { + describe('getSignatureDecodingEventProps', () => { + it('returns empty object when decoding API is disabled', () => { + const mockRequest = { + ...mockSignatureRequest, + decodingData: { + stateChanges: [], + error: undefined, + }, + } satisfies SignatureRequest; + + const result = getSignatureDecodingEventProps(mockRequest, false); + expect(result).toEqual({}); + }); + + it('returns empty object when no decodingData is present', () => { + const mockRequest = {} as SignatureRequest; + const result = getSignatureDecodingEventProps(mockRequest, true); + expect(result).toEqual({}); + }); + + it('returns no change response when stateChanges are empty', () => { + const mockRequest = { + ...mockSignatureRequest, + decodingData: { + stateChanges: [], + error: undefined, + }, + decodingLoading: false, + } satisfies SignatureRequest; + + const result = getSignatureDecodingEventProps(mockRequest, true); + expect(result).toEqual({ + decoding_change_types: [], + decoding_description: null, + decoding_response: 'NO_CHANGE', + }); + }); + + it('returns loading response when decodingLoading is true', () => { + const mockRequest = { + ...mockSignatureRequest, + decodingData: { + stateChanges: [], + error: undefined, + }, + decodingLoading: true, + } satisfies SignatureRequest; + + const result = getSignatureDecodingEventProps(mockRequest, true); + expect(result).toEqual({ + decoding_change_types: [], + decoding_description: null, + decoding_response: 'decoding_in_progress', + }); + }); + + it('returns error response when error exists', () => { + const mockRequest = { + ...mockSignatureRequest, + decodingData: { + stateChanges: [], + error: { + type: 'ERROR_TYPE', + message: 'Error message', + }, + }, + decodingLoading: false, + } satisfies SignatureRequest; + + const result = getSignatureDecodingEventProps(mockRequest, true); + expect(result).toEqual({ + decoding_change_types: [], + decoding_description: 'Error message', + decoding_response: 'ERROR_TYPE', + }); + }); + + it('returns change response when stateChanges exist', () => { + const mockRequest = { + ...mockSignatureRequest, + decodingData: { + stateChanges: [ + { changeType: DecodingDataChangeType.Approve, assetType: 'ERC20', address: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', amount: '12345', contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f' }, + { changeType: DecodingDataChangeType.Transfer, assetType: 'ERC20', address: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', amount: '12345', contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f' }, + ], + error: undefined, + }, + decodingLoading: false, + } satisfies SignatureRequest; + + const result = getSignatureDecodingEventProps(mockRequest, true); + expect(result).toEqual({ + decoding_change_types: ['APPROVE', 'TRANSFER'], + decoding_description: null, + decoding_response: 'CHANGE', + }); + }); + }); +}); From b6cc762ca9275a04fa82d3f29c10325c2cf11db6 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:48:17 -0800 Subject: [PATCH 04/17] test: add SignatureBlockaidBanner decoding metrics test --- .../SignatureBlockaidBanner.test.tsx | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx index e7d626e3030..8415e32c453 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx @@ -7,17 +7,27 @@ import { typedSignV1ConfirmationState, } from '../../../../../../util/test/confirm-data-helpers'; import SignatureBlockaidBanner from './index'; +import { DecodingDataChangeType, MessageParamsTyped } from '@metamask/signature-controller'; +import { Hex } from '@metamask/utils'; jest.mock('react-native-gzip', () => ({ deflate: (str: string) => str, })); const mockTrackEvent = jest.fn(); +const mockCreateEventBuilderAddProperties = jest.fn(); + +jest.mock('../../../hooks/useTypedSignSimulationEnabled', () => ({ + useTypedSignSimulationEnabled: () => true, +})); + jest.mock('../../../../../hooks/useMetrics', () => ({ useMetrics: () => ({ trackEvent: mockTrackEvent, createEventBuilder: () => ({ - addProperties: () => ({ build: () => ({}) }), + addProperties: mockCreateEventBuilderAddProperties.mockReturnValue({ + build: () => ({}), + }), }), }), })); @@ -36,12 +46,54 @@ const typedSignV1ConfirmationStateWithBlockaidResponse = { ...typedSignV1ConfirmationState.engine.backgroundState, ApprovalController: { pendingApprovals: { - 'fb2029e1-b0ab-11ef-9227-05a11087c334': { + '7e62bcb1-a4e9-11ef-9b51-ddf21c91a998': { ...typedSignApproval, requestData: { ...typedSignApproval.requestData, securityAlertResponse, }, + decodingData: { + stateChanges: [ + { + assetType: 'ERC20', + changeType: DecodingDataChangeType.Approve, + address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', + amount: '12345', + contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + ], + decodingLoading: false, + error: undefined, + }, + }, + }, + }, + SignatureController: { + signatureRequests: { + '7e62bcb1-a4e9-11ef-9b51-ddf21c91a998': { + chainId: '0x1' as Hex, + messageParams: { + ...typedSignApproval.requestData, + } as MessageParamsTyped, + decodingData: { + stateChanges: [ + { + assetType: 'ERC20', + changeType: DecodingDataChangeType.Approve, + address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', + amount: '12345', + contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + ], + error: undefined, + }, + }, + }, + }, + RemoteFeatureFlagController: { + remoteFeatureFlags: { + confirmation_redesign: { + signatures: true, }, }, }, @@ -71,8 +123,18 @@ describe('Confirm', () => { state: typedSignV1ConfirmationStateWithBlockaidResponse, }, ); + fireEvent.press(getByTestId('accordionheader')); fireEvent.press(getByText('Report an issue')); + expect(mockTrackEvent).toHaveBeenCalledTimes(1); + expect(mockCreateEventBuilderAddProperties).toHaveBeenCalledWith( + expect.objectContaining({ + decoding_change_types: ['APPROVE'], + decoding_description: null, + decoding_response: 'CHANGE', + external_link_clicked: 'security_alert_support_link', + }), + ); }); }); From 8b6ec71460c64a36580db637e92974f31590f825 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:17:36 -0800 Subject: [PATCH 05/17] feat: add decoding metrics for signature approved and rejected --- .../SignatureBlockaidBanner.tsx | 2 +- .../components/PersonalSign/PersonalSign.tsx | 20 +++++++++-- .../components/TypedSign/index.js | 36 +++++++++++++++++-- app/util/confirmation/signatureUtils.js | 17 ++++++--- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx index 56fe7001f16..d7800c588b2 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx @@ -42,7 +42,7 @@ const SignatureBlockaidBanner = () => { .addProperties(eventProps) .build(), ); - }, [trackEvent, createEventBuilder, signatureRequest, type, fromAddress]); + }, [trackEvent, createEventBuilder, signatureRequest, type, fromAddress, isSimulationEnabled]); return ( { await onReject(); showWalletConnectNotification(false); + + const eventProps = { + ...getAnalyticsParams(), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), + }; + trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_REJECTED) - .addProperties(getAnalyticsParams()) + .addProperties(eventProps) .build(), ); }; @@ -185,9 +195,15 @@ const PersonalSign = ({ if (!isExternalHardwareAccount(messageParams.from)) { await onConfirm(); showWalletConnectNotification(true); + + const eventProps = { + ...getAnalyticsParams(), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), + }; + trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_APPROVED) - .addProperties(getAnalyticsParams()) + .addProperties(eventProps) .build(), ); } else { diff --git a/app/components/Views/confirmations/components/TypedSign/index.js b/app/components/Views/confirmations/components/TypedSign/index.js index c56dc4c52bf..ccff7acdec7 100644 --- a/app/components/Views/confirmations/components/TypedSign/index.js +++ b/app/components/Views/confirmations/components/TypedSign/index.js @@ -29,8 +29,12 @@ import { isExternalHardwareAccount } from '../../../../../util/address'; import createExternalSignModelNav from '../../../../../util/hardwareWallet/signatureUtils'; import { SigningBottomSheetSelectorsIDs } from '../../../../../../e2e/selectors/Browser/SigningBottomSheet.selectors'; import { withMetricsAwareness } from '../../../../../components/hooks/useMetrics'; +import { selectPendingApprovals } from '../../../../../selectors/approvalController'; import { selectNetworkTypeByChainId } from '../../../../../selectors/networkController'; -import { selectSignatureRequestById } from '../../../../../selectors/signatureController'; +import { + selectSignatureRequestById, + selectTypedSignSimulationEnabled, +} from '../../../../../selectors/signatureController'; const createStyles = (colors) => StyleSheet.create({ @@ -90,6 +94,14 @@ class TypedSign extends PureComponent { * Indicated whether or not the expanded message is shown */ showExpandedMessage: PropTypes.bool, + /** + * Indicated whether or not the simulation is enabled + */ + isSimulationEnabled: PropTypes.bool, + /** + * Signature request object + */ + signatureRequest: PropTypes.object, /** * Security alert response object */ @@ -110,14 +122,16 @@ class TypedSign extends PureComponent { componentDidMount = () => { const { + isSimulationEnabled, messageParams: { metamaskId }, messageParams, metrics, + signatureRequest, } = this.props; const eventProps = { ...getAnalyticsParams(messageParams, 'typed_sign'), - ...getSignatureDecodingEventProps(messageParams), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), }; metrics.trackEvent( @@ -152,23 +166,33 @@ class TypedSign extends PureComponent { }; rejectSignature = async () => { - const { messageParams, onReject, securityAlertResponse } = this.props; + const { + isSimulationEnabled, + messageParams, + onReject, + securityAlertResponse, + signatureRequest, + } = this.props; + await handleSignatureAction( onReject, messageParams, typedSign[messageParams.version], securityAlertResponse, false, + { isSimulationEnabled, signatureRequest }, ); }; confirmSignature = async () => { const { + isSimulationEnabled, messageParams, onConfirm, onReject, navigation, securityAlertResponse, + signatureRequest, } = this.props; if (!isExternalHardwareAccount(messageParams.from)) { await handleSignatureAction( @@ -177,6 +201,7 @@ class TypedSign extends PureComponent { typedSign[messageParams.version], securityAlertResponse, true, + { isSimulationEnabled, signatureRequest }, ); } else { navigation.navigate( @@ -315,8 +340,13 @@ const mapStateToProps = (state, ownProps) => { ); return { + isSimulationEnabled: selectTypedSignSimulationEnabled( + state, + signatureRequest?.id, + ), networkType: selectNetworkTypeByChainId(state, signatureRequest?.chainId), securityAlertResponse: state.signatureRequest.securityAlertResponse, + signatureRequest: Object.values(selectPendingApprovals(state) || {})[0], }; }; diff --git a/app/util/confirmation/signatureUtils.js b/app/util/confirmation/signatureUtils.js index bc09a742b5f..fd70e9eb850 100644 --- a/app/util/confirmation/signatureUtils.js +++ b/app/util/confirmation/signatureUtils.js @@ -6,6 +6,7 @@ import { WALLET_CONNECT_ORIGIN } from '../walletconnect'; import AppConstants from '../../core/AppConstants'; import { InteractionManager } from 'react-native'; import { strings } from '../../../locales/i18n'; +import { getSignatureDecodingEventProps } from '../../components/Views/confirmations/utils/signatureMetrics'; import { selectChainId } from '../../selectors/networkController'; import { store } from '../../store'; import { getBlockaidMetricsParams } from '../blockaid'; @@ -13,7 +14,6 @@ import Device from '../device'; import { getDecimalChainId } from '../networks'; import Logger from '../Logger'; import { MetricsEventBuilder } from '../../core/Analytics/MetricsEventBuilder'; - export const typedSign = { V1: 'eth_signTypedData', V3: 'eth_signTypedData_v3', @@ -102,18 +102,27 @@ export const handleSignatureAction = async ( signType, securityAlertResponse, confirmation, + { + isSimulationEnabled, + signatureRequest, + } ) => { await onAction(); showWalletConnectNotification(messageParams, confirmation); + MetaMetrics.getInstance().trackEvent( MetricsEventBuilder.createEventBuilder( confirmation ? MetaMetricsEvents.SIGNATURE_APPROVED : MetaMetricsEvents.SIGNATURE_REJECTED, ) - .addProperties( - getAnalyticsParams(messageParams, signType, securityAlertResponse), - ) + .addProperties({ + ...getAnalyticsParams(messageParams, signType, securityAlertResponse), + ...getSignatureDecodingEventProps( + signatureRequest, + isSimulationEnabled, + ), + }) .build(), ); }; From 7de1a69a92dbceb573feb3b9a1f0adfae5f35432 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:25:50 -0800 Subject: [PATCH 06/17] fix: support pendingApprovals case isSimulationEnabled --- .../Views/confirmations/components/SignatureRequest/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Views/confirmations/components/SignatureRequest/index.js b/app/components/Views/confirmations/components/SignatureRequest/index.js index ee4ce184cd0..aec69d3020a 100644 --- a/app/components/Views/confirmations/components/SignatureRequest/index.js +++ b/app/components/Views/confirmations/components/SignatureRequest/index.js @@ -423,7 +423,7 @@ class SignatureRequest extends PureComponent { } const mapStateToProps = (state) => ({ - isSimulationEnabled: selectTypedSignSimulationEnabled(state, Object.values(selectPendingApprovals(state) || {})[0].id), + isSimulationEnabled: selectTypedSignSimulationEnabled(state, Object.values(selectPendingApprovals(state) || {})[0]?.id), securityAlertResponse: state.signatureRequest.securityAlertResponse, selectedAddress: selectSelectedInternalAccountFormattedAddress(state), signatureRequest: Object.values(selectPendingApprovals(state) || {})[0], From 4dc981bab21463b64f238a769a55021e87c78d6f Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:39:29 -0800 Subject: [PATCH 07/17] test:fix: useSignatureMetrics test --- .../hooks/useSignatureMetrics.test.ts | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/components/Views/confirmations/hooks/useSignatureMetrics.test.ts b/app/components/Views/confirmations/hooks/useSignatureMetrics.test.ts index 81b42db4be5..05f6b9d1f84 100644 --- a/app/components/Views/confirmations/hooks/useSignatureMetrics.test.ts +++ b/app/components/Views/confirmations/hooks/useSignatureMetrics.test.ts @@ -1,9 +1,10 @@ import { MetaMetricsEvents } from '../../../../core/Analytics'; import { renderHookWithProvider } from '../../../../util/test/renderWithProvider'; import { useSignatureMetrics } from './useSignatureMetrics'; +import { SignatureRequestType, SignatureRequest } from '@metamask/signature-controller'; const mockSigRequest = { - type: 'personal_sign', + type: SignatureRequestType.PersonalSign, messageParams: { data: '0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765', from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', @@ -16,8 +17,8 @@ const mockSigRequest = { origin: 'metamask.github.io', metamaskId: '76b33b40-7b5c-11ef-bc0a-25bce29dbc09', }, - chainId: '0x0', -}; + chainId: '0x1' as `0x${string}`, +} as const; jest.mock('./useSignatureRequest', () => ({ useSignatureRequest: () => mockSigRequest, @@ -41,7 +42,20 @@ describe('useSignatureMetrics', () => { }); it('should capture metrics events correctly', async () => { const { result } = renderHookWithProvider(() => useSignatureMetrics(), { - state: {}, + state: { + engine: { + backgroundState: { + PreferencesController: { + useTransactionSimulations: true, + }, + SignatureController: { + signatureRequests: { + [mockSigRequest.messageParams.metamaskId]: mockSigRequest, + } as unknown as Record, + }, + }, + }, + }, }); // first call for 'SIGNATURE_REQUESTED' event expect(mockTrackEvent).toHaveBeenCalledTimes(1); From 302a0016d078d80f565d0136d95ff03d21ef9db7 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:29:14 -0800 Subject: [PATCH 08/17] revert: decoding metric on SignatureBlockaidBanner --- .../SignatureBlockaidBanner.test.tsx | 16 ---------------- .../SignatureBlockaidBanner.tsx | 6 +----- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx index 8415e32c453..89f74757037 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx @@ -52,19 +52,6 @@ const typedSignV1ConfirmationStateWithBlockaidResponse = { ...typedSignApproval.requestData, securityAlertResponse, }, - decodingData: { - stateChanges: [ - { - assetType: 'ERC20', - changeType: DecodingDataChangeType.Approve, - address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', - amount: '12345', - contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', - }, - ], - decodingLoading: false, - error: undefined, - }, }, }, }, @@ -130,9 +117,6 @@ describe('Confirm', () => { expect(mockTrackEvent).toHaveBeenCalledTimes(1); expect(mockCreateEventBuilderAddProperties).toHaveBeenCalledWith( expect.objectContaining({ - decoding_change_types: ['APPROVE'], - decoding_description: null, - decoding_response: 'CHANGE', external_link_clicked: 'security_alert_support_link', }), ); diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx index d7800c588b2..4dc044a1f85 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx @@ -7,14 +7,11 @@ import { useMetrics } from '../../../../../hooks/useMetrics'; import BlockaidBanner from '../../../components/BlockaidBanner/BlockaidBanner'; import useApprovalRequest from '../../../hooks/useApprovalRequest'; import { useSignatureRequest } from '../../../hooks/useSignatureRequest'; -import { getSignatureDecodingEventProps } from '../../../utils/signatureMetrics'; import styleSheet from './SignatureBlockaidBanner.styles'; -import { useTypedSignSimulationEnabled } from '../../../hooks/useTypedSignSimulationEnabled'; const SignatureBlockaidBanner = () => { const { approvalRequest } = useApprovalRequest(); const signatureRequest = useSignatureRequest(); - const isSimulationEnabled = useTypedSignSimulationEnabled(); const { trackEvent, createEventBuilder } = useMetrics(); const { styles } = useStyles(styleSheet, {}); @@ -33,7 +30,6 @@ const SignatureBlockaidBanner = () => { }, type, ), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), external_link_clicked: 'security_alert_support_link', }; @@ -42,7 +38,7 @@ const SignatureBlockaidBanner = () => { .addProperties(eventProps) .build(), ); - }, [trackEvent, createEventBuilder, signatureRequest, type, fromAddress, isSimulationEnabled]); + }, [trackEvent, createEventBuilder, type, fromAddress]); return ( Date: Fri, 17 Jan 2025 09:55:23 -0800 Subject: [PATCH 09/17] Revert "feat: add decoding metrics for signature approved and rejected" This reverts commit 8b6ec71460c64a36580db637e92974f31590f825. --- .../components/PersonalSign/PersonalSign.tsx | 20 ++--------- .../components/TypedSign/index.js | 36 ++----------------- app/util/confirmation/signatureUtils.js | 17 +++------ 3 files changed, 9 insertions(+), 64 deletions(-) diff --git a/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx b/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx index a1973758050..9a71d739877 100644 --- a/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx +++ b/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx @@ -32,8 +32,6 @@ import { selectSignatureRequestById } from '../../../../../selectors/signatureCo import { selectNetworkTypeByChainId } from '../../../../../selectors/networkController'; import { RootState } from '../../../../../reducers'; import { Hex } from '@metamask/utils'; -import { getSignatureDecodingEventProps } from '../../utils/signatureMetrics'; -import { useTypedSignSimulationEnabled } from '../../hooks/useTypedSignSimulationEnabled'; /** * Converts a hexadecimal string to a utf8 string. @@ -84,8 +82,6 @@ const PersonalSign = ({ selectNetworkTypeByChainId(state, chainId as Hex), ); - const isSimulationEnabled = useTypedSignSimulationEnabled(); - // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any const { colors }: any = useTheme(); @@ -178,15 +174,9 @@ const PersonalSign = ({ const rejectSignature = async () => { await onReject(); showWalletConnectNotification(false); - - const eventProps = { - ...getAnalyticsParams(), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), - }; - trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_REJECTED) - .addProperties(eventProps) + .addProperties(getAnalyticsParams()) .build(), ); }; @@ -195,15 +185,9 @@ const PersonalSign = ({ if (!isExternalHardwareAccount(messageParams.from)) { await onConfirm(); showWalletConnectNotification(true); - - const eventProps = { - ...getAnalyticsParams(), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), - }; - trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_APPROVED) - .addProperties(eventProps) + .addProperties(getAnalyticsParams()) .build(), ); } else { diff --git a/app/components/Views/confirmations/components/TypedSign/index.js b/app/components/Views/confirmations/components/TypedSign/index.js index ccff7acdec7..c56dc4c52bf 100644 --- a/app/components/Views/confirmations/components/TypedSign/index.js +++ b/app/components/Views/confirmations/components/TypedSign/index.js @@ -29,12 +29,8 @@ import { isExternalHardwareAccount } from '../../../../../util/address'; import createExternalSignModelNav from '../../../../../util/hardwareWallet/signatureUtils'; import { SigningBottomSheetSelectorsIDs } from '../../../../../../e2e/selectors/Browser/SigningBottomSheet.selectors'; import { withMetricsAwareness } from '../../../../../components/hooks/useMetrics'; -import { selectPendingApprovals } from '../../../../../selectors/approvalController'; import { selectNetworkTypeByChainId } from '../../../../../selectors/networkController'; -import { - selectSignatureRequestById, - selectTypedSignSimulationEnabled, -} from '../../../../../selectors/signatureController'; +import { selectSignatureRequestById } from '../../../../../selectors/signatureController'; const createStyles = (colors) => StyleSheet.create({ @@ -94,14 +90,6 @@ class TypedSign extends PureComponent { * Indicated whether or not the expanded message is shown */ showExpandedMessage: PropTypes.bool, - /** - * Indicated whether or not the simulation is enabled - */ - isSimulationEnabled: PropTypes.bool, - /** - * Signature request object - */ - signatureRequest: PropTypes.object, /** * Security alert response object */ @@ -122,16 +110,14 @@ class TypedSign extends PureComponent { componentDidMount = () => { const { - isSimulationEnabled, messageParams: { metamaskId }, messageParams, metrics, - signatureRequest, } = this.props; const eventProps = { ...getAnalyticsParams(messageParams, 'typed_sign'), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), + ...getSignatureDecodingEventProps(messageParams), }; metrics.trackEvent( @@ -166,33 +152,23 @@ class TypedSign extends PureComponent { }; rejectSignature = async () => { - const { - isSimulationEnabled, - messageParams, - onReject, - securityAlertResponse, - signatureRequest, - } = this.props; - + const { messageParams, onReject, securityAlertResponse } = this.props; await handleSignatureAction( onReject, messageParams, typedSign[messageParams.version], securityAlertResponse, false, - { isSimulationEnabled, signatureRequest }, ); }; confirmSignature = async () => { const { - isSimulationEnabled, messageParams, onConfirm, onReject, navigation, securityAlertResponse, - signatureRequest, } = this.props; if (!isExternalHardwareAccount(messageParams.from)) { await handleSignatureAction( @@ -201,7 +177,6 @@ class TypedSign extends PureComponent { typedSign[messageParams.version], securityAlertResponse, true, - { isSimulationEnabled, signatureRequest }, ); } else { navigation.navigate( @@ -340,13 +315,8 @@ const mapStateToProps = (state, ownProps) => { ); return { - isSimulationEnabled: selectTypedSignSimulationEnabled( - state, - signatureRequest?.id, - ), networkType: selectNetworkTypeByChainId(state, signatureRequest?.chainId), securityAlertResponse: state.signatureRequest.securityAlertResponse, - signatureRequest: Object.values(selectPendingApprovals(state) || {})[0], }; }; diff --git a/app/util/confirmation/signatureUtils.js b/app/util/confirmation/signatureUtils.js index fd70e9eb850..bc09a742b5f 100644 --- a/app/util/confirmation/signatureUtils.js +++ b/app/util/confirmation/signatureUtils.js @@ -6,7 +6,6 @@ import { WALLET_CONNECT_ORIGIN } from '../walletconnect'; import AppConstants from '../../core/AppConstants'; import { InteractionManager } from 'react-native'; import { strings } from '../../../locales/i18n'; -import { getSignatureDecodingEventProps } from '../../components/Views/confirmations/utils/signatureMetrics'; import { selectChainId } from '../../selectors/networkController'; import { store } from '../../store'; import { getBlockaidMetricsParams } from '../blockaid'; @@ -14,6 +13,7 @@ import Device from '../device'; import { getDecimalChainId } from '../networks'; import Logger from '../Logger'; import { MetricsEventBuilder } from '../../core/Analytics/MetricsEventBuilder'; + export const typedSign = { V1: 'eth_signTypedData', V3: 'eth_signTypedData_v3', @@ -102,27 +102,18 @@ export const handleSignatureAction = async ( signType, securityAlertResponse, confirmation, - { - isSimulationEnabled, - signatureRequest, - } ) => { await onAction(); showWalletConnectNotification(messageParams, confirmation); - MetaMetrics.getInstance().trackEvent( MetricsEventBuilder.createEventBuilder( confirmation ? MetaMetricsEvents.SIGNATURE_APPROVED : MetaMetricsEvents.SIGNATURE_REJECTED, ) - .addProperties({ - ...getAnalyticsParams(messageParams, signType, securityAlertResponse), - ...getSignatureDecodingEventProps( - signatureRequest, - isSimulationEnabled, - ), - }) + .addProperties( + getAnalyticsParams(messageParams, signType, securityAlertResponse), + ) .build(), ); }; From 3c1e5e337632f0a8b8acdcb8085736fff51c00b2 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:55:47 -0800 Subject: [PATCH 10/17] Revert "refactor: separate selector from hook useTypedSignSimulationEnabled" This reverts commit bccc48966e369f048475803fdfbd1a655a0a2232. --- .../hooks/useTypedSignSimulationEnabled.ts | 62 +++++++++++++++++-- .../confirmations/utils/signatureDecoding.ts | 33 ---------- app/selectors/signatureController.ts | 33 +--------- 3 files changed, 59 insertions(+), 69 deletions(-) delete mode 100644 app/components/Views/confirmations/utils/signatureDecoding.ts diff --git a/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts b/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts index 300fb11e7d5..0553f8fcae2 100644 --- a/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts +++ b/app/components/Views/confirmations/hooks/useTypedSignSimulationEnabled.ts @@ -1,12 +1,66 @@ import { useSelector } from 'react-redux'; -import { selectTypedSignSimulationEnabled } from '../../../../selectors/signatureController'; -import { RootState } from '../../../UI/BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal.test'; +import { SignTypedDataVersion } from '@metamask/eth-sig-util'; +import { MessageParamsTyped, SignatureRequest, SignatureRequestType } from '@metamask/signature-controller'; +import { selectUseTransactionSimulations } from '../../../../selectors/preferencesController'; +import { isRecognizedPermit, parseTypedDataMessage } from '../utils/signature'; import { useSignatureRequest } from './useSignatureRequest'; +const NON_PERMIT_SUPPORTED_TYPES_SIGNS = [ + { + domainName: 'Seaport', + primaryTypeList: ['BulkOrder'], + versionList: ['1.4', '1.5', '1.6'], + }, + { + domainName: 'Seaport', + primaryTypeList: ['OrderComponents'], + }, +]; + +const isNonPermitSupportedByDecodingAPI = ( + signatureRequest: SignatureRequest, +) => { + const data = signatureRequest.messageParams?.data as string; + if (!data) { return false; } + + const { + domain: { name, version }, + primaryType, + } = parseTypedDataMessage(data); + + return NON_PERMIT_SUPPORTED_TYPES_SIGNS.some( + ({ domainName, primaryTypeList, versionList }) => + name === domainName && + primaryTypeList.includes(primaryType) && + (!versionList || versionList.includes(version)), + ); +}; + export function useTypedSignSimulationEnabled() { const signatureRequest = useSignatureRequest(); + const useTransactionSimulations = useSelector( + selectUseTransactionSimulations, + ); + + if (!signatureRequest) { + return undefined; + } + + const requestType = signatureRequest.type; + const signatureMethod = (signatureRequest.messageParams as MessageParamsTyped)?.version; + + const isTypedSignV3V4 = requestType === SignatureRequestType.TypedSign && ( + signatureMethod === SignTypedDataVersion.V3 || + signatureMethod === SignTypedDataVersion.V4 + ); + const isPermit = isRecognizedPermit(signatureRequest); + + const nonPermitSupportedByDecodingAPI: boolean = + isTypedSignV3V4 && isNonPermitSupportedByDecodingAPI(signatureRequest); - return useSelector((state: RootState) => - selectTypedSignSimulationEnabled(state, signatureRequest?.id as string) + return ( + useTransactionSimulations && + isTypedSignV3V4 && + (isPermit || nonPermitSupportedByDecodingAPI) ); } diff --git a/app/components/Views/confirmations/utils/signatureDecoding.ts b/app/components/Views/confirmations/utils/signatureDecoding.ts deleted file mode 100644 index 9adc4b8dd8b..00000000000 --- a/app/components/Views/confirmations/utils/signatureDecoding.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { SignatureRequest } from '@metamask/signature-controller'; -import { parseTypedDataMessage } from './signature'; - -const NON_PERMIT_SUPPORTED_TYPES_SIGNS = [ - { - domainName: 'Seaport', - primaryTypeList: ['BulkOrder'], - versionList: ['1.4', '1.5', '1.6'], - }, - { - domainName: 'Seaport', - primaryTypeList: ['OrderComponents'], - }, -]; - -export const isNonPermitSupportedByDecodingAPI = ( - signatureRequest: SignatureRequest, -) => { - const data = signatureRequest.messageParams?.data as string; - if (!data) { return false; } - - const { - domain: { name, version }, - primaryType, - } = parseTypedDataMessage(data); - - return NON_PERMIT_SUPPORTED_TYPES_SIGNS.some( - ({ domainName, primaryTypeList, versionList }) => - name === domainName && - primaryTypeList.includes(primaryType) && - (!versionList || versionList.includes(version)), - ); -}; diff --git a/app/selectors/signatureController.ts b/app/selectors/signatureController.ts index 1e83dca1903..8d9ba0f9ead 100644 --- a/app/selectors/signatureController.ts +++ b/app/selectors/signatureController.ts @@ -1,8 +1,4 @@ -import { SignTypedDataVersion } from '@metamask/eth-sig-util'; -import { MessageParamsTyped, SignatureRequest, SignatureRequestType } from '@metamask/signature-controller'; -import { selectUseTransactionSimulations } from './preferencesController'; -import { isRecognizedPermit } from '../components/Views/confirmations/utils/signature'; -import { isNonPermitSupportedByDecodingAPI } from '../components/Views/confirmations/utils/signatureDecoding'; +import { SignatureRequest } from '@metamask/signature-controller'; import { RootState } from '../reducers'; import { createDeepEqualSelector } from './util'; @@ -20,30 +16,3 @@ export const selectSignatureRequestById = createDeepEqualSelector( (signatureRequests, id) => signatureRequests[id] as SignatureRequest | undefined, ); - -export const selectTypedSignSimulationEnabled = createDeepEqualSelector( - [selectSignatureRequestById, selectUseTransactionSimulations], - (signatureRequest, useTransactionSimulations) => { - if (!signatureRequest) { - return undefined; - } - - const requestType = signatureRequest.type; - const signatureMethod = (signatureRequest.messageParams as MessageParamsTyped)?.version; - - const isTypedSignV3V4 = requestType === SignatureRequestType.TypedSign && ( - signatureMethod === SignTypedDataVersion.V3 || - signatureMethod === SignTypedDataVersion.V4 - ); - const isPermit = isRecognizedPermit(signatureRequest); - - const nonPermitSupportedByDecodingAPI: boolean = - isTypedSignV3V4 && isNonPermitSupportedByDecodingAPI(signatureRequest); - - return ( - useTransactionSimulations && - isTypedSignV3V4 && - (isPermit || nonPermitSupportedByDecodingAPI) - ); - } -); From 0f8456db6ce67082f1012312084f8a0a9ee02074 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:08:02 -0800 Subject: [PATCH 11/17] revert: decoding metrics on SignatureBlockaidBanner --- .../SignatureBlockaidBanner.test.tsx | 18 +----------------- .../SignatureBlockaidBanner.tsx | 16 +++++++++------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx index 89f74757037..0b31760c0f5 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx @@ -7,7 +7,7 @@ import { typedSignV1ConfirmationState, } from '../../../../../../util/test/confirm-data-helpers'; import SignatureBlockaidBanner from './index'; -import { DecodingDataChangeType, MessageParamsTyped } from '@metamask/signature-controller'; +import { MessageParamsTyped } from '@metamask/signature-controller'; import { Hex } from '@metamask/utils'; jest.mock('react-native-gzip', () => ({ @@ -17,10 +17,6 @@ jest.mock('react-native-gzip', () => ({ const mockTrackEvent = jest.fn(); const mockCreateEventBuilderAddProperties = jest.fn(); -jest.mock('../../../hooks/useTypedSignSimulationEnabled', () => ({ - useTypedSignSimulationEnabled: () => true, -})); - jest.mock('../../../../../hooks/useMetrics', () => ({ useMetrics: () => ({ trackEvent: mockTrackEvent, @@ -62,18 +58,6 @@ const typedSignV1ConfirmationStateWithBlockaidResponse = { messageParams: { ...typedSignApproval.requestData, } as MessageParamsTyped, - decodingData: { - stateChanges: [ - { - assetType: 'ERC20', - changeType: DecodingDataChangeType.Approve, - address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', - amount: '12345', - contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', - }, - ], - error: undefined, - }, }, }, }, diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx index 4dc044a1f85..249025e158d 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx @@ -6,24 +6,22 @@ import { useStyles } from '../../../../../../component-library/hooks'; import { useMetrics } from '../../../../../hooks/useMetrics'; import BlockaidBanner from '../../../components/BlockaidBanner/BlockaidBanner'; import useApprovalRequest from '../../../hooks/useApprovalRequest'; -import { useSignatureRequest } from '../../../hooks/useSignatureRequest'; import styleSheet from './SignatureBlockaidBanner.styles'; const SignatureBlockaidBanner = () => { const { approvalRequest } = useApprovalRequest(); - const signatureRequest = useSignatureRequest(); const { trackEvent, createEventBuilder } = useMetrics(); const { styles } = useStyles(styleSheet, {}); const { type, - messageParams: { from: fromAddress }, - } = signatureRequest ?? { - messageParams: {}, + requestData: { from: fromAddress }, + } = approvalRequest ?? { + requestData: {}, }; const onContactUsClicked = useCallback(() => { - const eventProps = { + const analyticsParams = { ...getAnalyticsParams( { from: fromAddress, @@ -35,11 +33,15 @@ const SignatureBlockaidBanner = () => { trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_REQUESTED) - .addProperties(eventProps) + .addProperties(analyticsParams) .build(), ); }, [trackEvent, createEventBuilder, type, fromAddress]); + if (!approvalRequest?.requestData?.securityAlertResponse) { + return null; + } + return ( Date: Fri, 17 Jan 2025 10:08:44 -0800 Subject: [PATCH 12/17] revert: decoding metrics on old SignatureRequest --- .../components/SignatureRequest/index.js | 34 +++---------------- .../components/TypedSign/index.js | 6 ++-- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/app/components/Views/confirmations/components/SignatureRequest/index.js b/app/components/Views/confirmations/components/SignatureRequest/index.js index aec69d3020a..bccde7b1d36 100644 --- a/app/components/Views/confirmations/components/SignatureRequest/index.js +++ b/app/components/Views/confirmations/components/SignatureRequest/index.js @@ -22,8 +22,6 @@ import WebsiteIcon from '../../../../UI/WebsiteIcon'; import { getSignatureDecodingEventProps } from '../../utils/signatureMetrics'; import BlockaidBanner from '../BlockaidBanner/BlockaidBanner'; import { ResultType } from '../BlockaidBanner/BlockaidBanner.types'; -import { selectTypedSignSimulationEnabled } from '../../../../../selectors/signatureController'; -import { selectPendingApprovals } from '../../../../../selectors/approvalController'; const getCleanUrl = (url) => { try { @@ -146,14 +144,6 @@ class SignatureRequest extends PureComponent { * Object containing current page title and url */ currentPageInformation: PropTypes.object, - /** - * Whether signature simulation with decoding API is enabled - */ - isSimulationEnabled: PropTypes.bool, - /** - * Signature request object - */ - signatureRequest: PropTypes.object, /** * String representing signature type */ @@ -229,18 +219,7 @@ class SignatureRequest extends PureComponent { }; componentDidMount = () => { - const { currentPageInformation, isSimulationEnabled, type, fromAddress, signatureRequest } = this.props; - - const eventProps = { - ...getAnalyticsParams( - { - currentPageInformation, - from: fromAddress, - }, - type, - ), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), - }; + const { currentPageInformation, type, fromAddress } = this.props; this.props.metrics.trackEvent( this.props.metrics @@ -324,22 +303,21 @@ class SignatureRequest extends PureComponent { }; onContactUsClicked = () => { - const { fromAddress, isSimulationEnabled, type, signatureRequest } = this.props; + const { fromAddress, type } = this.props; - const eventProps = { + const analyticsParams = { ...getAnalyticsParams( { from: fromAddress, }, type, ), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), external_link_clicked: 'security_alert_support_link', }; this.props.metrics.trackEvent( this.props.metrics .createEventBuilder(MetaMetricsEvents.SIGNATURE_REQUESTED) - .addProperties(eventProps) + .addProperties(analyticsParams) .build(), ); }; @@ -423,10 +401,8 @@ class SignatureRequest extends PureComponent { } const mapStateToProps = (state) => ({ - isSimulationEnabled: selectTypedSignSimulationEnabled(state, Object.values(selectPendingApprovals(state) || {})[0]?.id), - securityAlertResponse: state.signatureRequest.securityAlertResponse, selectedAddress: selectSelectedInternalAccountFormattedAddress(state), - signatureRequest: Object.values(selectPendingApprovals(state) || {})[0], + securityAlertResponse: state.signatureRequest.securityAlertResponse, }); SignatureRequest.contextType = ThemeContext; diff --git a/app/components/Views/confirmations/components/TypedSign/index.js b/app/components/Views/confirmations/components/TypedSign/index.js index c56dc4c52bf..ac2484cd970 100644 --- a/app/components/Views/confirmations/components/TypedSign/index.js +++ b/app/components/Views/confirmations/components/TypedSign/index.js @@ -15,7 +15,6 @@ import { sanitizeString, } from '../../../../../util/string'; -import { getSignatureDecodingEventProps } from '../../utils/signatureMetrics'; import { addSignatureErrorListener, getAnalyticsParams, @@ -115,16 +114,19 @@ class TypedSign extends PureComponent { metrics, } = this.props; +<<<<<<< Updated upstream const eventProps = { ...getAnalyticsParams(messageParams, 'typed_sign'), ...getSignatureDecodingEventProps(messageParams), }; +======= +>>>>>>> Stashed changes metrics.trackEvent( MetricsEventBuilder.createEventBuilder( MetaMetricsEvents.SIGNATURE_REQUESTED, ) - .addProperties(eventProps) + .addProperties(getAnalyticsParams(messageParams, 'typed_sign')) .build(), ); addSignatureErrorListener(metamaskId, this.onSignatureError); From 02a456844ac387213fad357f4003dc9b85a7e2f5 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:14:56 -0800 Subject: [PATCH 13/17] refactor: cleanup --- .../SignatureBlockaidBanner.test.tsx | 19 ------------------- .../SignatureBlockaidBanner.tsx | 1 - .../components/SignatureRequest/index.js | 2 -- .../components/TypedSign/index.js | 8 -------- 4 files changed, 30 deletions(-) diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx index 0b31760c0f5..b3df9b6b440 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.test.tsx @@ -7,8 +7,6 @@ import { typedSignV1ConfirmationState, } from '../../../../../../util/test/confirm-data-helpers'; import SignatureBlockaidBanner from './index'; -import { MessageParamsTyped } from '@metamask/signature-controller'; -import { Hex } from '@metamask/utils'; jest.mock('react-native-gzip', () => ({ deflate: (str: string) => str, @@ -51,23 +49,6 @@ const typedSignV1ConfirmationStateWithBlockaidResponse = { }, }, }, - SignatureController: { - signatureRequests: { - '7e62bcb1-a4e9-11ef-9b51-ddf21c91a998': { - chainId: '0x1' as Hex, - messageParams: { - ...typedSignApproval.requestData, - } as MessageParamsTyped, - }, - }, - }, - RemoteFeatureFlagController: { - remoteFeatureFlags: { - confirmation_redesign: { - signatures: true, - }, - }, - }, }, }, }; diff --git a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx index 249025e158d..198f2290376 100644 --- a/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx +++ b/app/components/Views/confirmations/components/Confirm/SignatureBlockaidBanner/SignatureBlockaidBanner.tsx @@ -30,7 +30,6 @@ const SignatureBlockaidBanner = () => { ), external_link_clicked: 'security_alert_support_link', }; - trackEvent( createEventBuilder(MetaMetricsEvents.SIGNATURE_REQUESTED) .addProperties(analyticsParams) diff --git a/app/components/Views/confirmations/components/SignatureRequest/index.js b/app/components/Views/confirmations/components/SignatureRequest/index.js index bccde7b1d36..9ba8a8eaf0c 100644 --- a/app/components/Views/confirmations/components/SignatureRequest/index.js +++ b/app/components/Views/confirmations/components/SignatureRequest/index.js @@ -19,7 +19,6 @@ import ActionView, { ConfirmButtonState } from '../../../../UI/ActionView'; import QRSigningDetails from '../../../../UI/QRHardware/QRSigningDetails'; import withQRHardwareAwareness from '../../../../UI/QRHardware/withQRHardwareAwareness'; import WebsiteIcon from '../../../../UI/WebsiteIcon'; -import { getSignatureDecodingEventProps } from '../../utils/signatureMetrics'; import BlockaidBanner from '../BlockaidBanner/BlockaidBanner'; import { ResultType } from '../BlockaidBanner/BlockaidBanner.types'; @@ -304,7 +303,6 @@ class SignatureRequest extends PureComponent { onContactUsClicked = () => { const { fromAddress, type } = this.props; - const analyticsParams = { ...getAnalyticsParams( { diff --git a/app/components/Views/confirmations/components/TypedSign/index.js b/app/components/Views/confirmations/components/TypedSign/index.js index ac2484cd970..04953a7865e 100644 --- a/app/components/Views/confirmations/components/TypedSign/index.js +++ b/app/components/Views/confirmations/components/TypedSign/index.js @@ -114,14 +114,6 @@ class TypedSign extends PureComponent { metrics, } = this.props; -<<<<<<< Updated upstream - const eventProps = { - ...getAnalyticsParams(messageParams, 'typed_sign'), - ...getSignatureDecodingEventProps(messageParams), - }; - -======= ->>>>>>> Stashed changes metrics.trackEvent( MetricsEventBuilder.createEventBuilder( MetaMetricsEvents.SIGNATURE_REQUESTED, From 024a5a753bc3eb1c24416f41abc34556ddb8ecdc Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:35:46 -0800 Subject: [PATCH 14/17] fix: isRecognizedPermit should only call parseTypedDataMessage for TypedSign requests --- app/components/Views/confirmations/utils/signature.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/Views/confirmations/utils/signature.ts b/app/components/Views/confirmations/utils/signature.ts index 9035a2b3087..5c30d885f78 100644 --- a/app/components/Views/confirmations/utils/signature.ts +++ b/app/components/Views/confirmations/utils/signature.ts @@ -1,4 +1,4 @@ -import { SignatureRequest } from '@metamask/signature-controller'; +import { SignatureRequest, SignatureRequestType } from '@metamask/signature-controller'; import { PRIMARY_TYPES_PERMIT } from '../constants/signatures'; /** @@ -50,7 +50,7 @@ export const parseTypedDataMessage = (dataToParse: string) => { * @param request - The signature request to check */ export const isRecognizedPermit = (request: SignatureRequest) => { - if (!request) { + if (!request || request.type !== SignatureRequestType.TypedSign) { return false; } From fa571e59621b9e1e3bcac0aa06530b54289f1677 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:36:10 -0800 Subject: [PATCH 15/17] refactor: useSignatureMetrics getAnalyticsParams with decoding metrics --- .../hooks/useSignatureMetrics.ts | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/app/components/Views/confirmations/hooks/useSignatureMetrics.ts b/app/components/Views/confirmations/hooks/useSignatureMetrics.ts index 2ad614affad..165d079afcf 100644 --- a/app/components/Views/confirmations/hooks/useSignatureMetrics.ts +++ b/app/components/Views/confirmations/hooks/useSignatureMetrics.ts @@ -13,6 +13,7 @@ import { isSignatureRequest } from '../utils/confirm'; import { getSignatureDecodingEventProps } from '../utils/signatureMetrics'; import { useSignatureRequest } from './useSignatureRequest'; import { useTypedSignSimulationEnabled } from './useTypedSignSimulationEnabled'; +import { SignatureRequest } from '@metamask/signature-controller'; interface MessageParamsType { meta: Record; @@ -22,11 +23,16 @@ interface MessageParamsType { } const getAnalyticsParams = ( - messageParams: MessageParamsType, - type: string, - chainId?: Hex, + signatureRequest: SignatureRequest, + isSimulationEnabled?: boolean, ) => { - const { meta = {}, from, securityAlertResponse, version } = messageParams; + const { chainId, messageParams, type } = signatureRequest ?? {}; + const { + meta = {}, + from, + securityAlertResponse, + version + } = (messageParams as unknown as MessageParamsType) || {}; return { account_type: getAddressAccountType(from as string), @@ -39,6 +45,7 @@ const getAnalyticsParams = ( ...(securityAlertResponse ? getBlockaidMetricsParams(securityAlertResponse) : {}), + ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), }; }; @@ -46,7 +53,7 @@ export const useSignatureMetrics = () => { const signatureRequest = useSignatureRequest(); const isSimulationEnabled = useTypedSignSimulationEnabled(); - const { chainId, messageParams, type } = signatureRequest ?? {}; + const type = signatureRequest?.type; const captureSignatureMetrics = useCallback( async ( @@ -56,22 +63,18 @@ export const useSignatureMetrics = () => { return; } - const eventProps = { - ...getAnalyticsParams( - messageParams as unknown as MessageParamsType, - type, - chainId, - ), - ...getSignatureDecodingEventProps(signatureRequest, isSimulationEnabled), - }; - MetaMetrics.getInstance().trackEvent( MetricsEventBuilder.createEventBuilder(event) - .addProperties(eventProps) + .addProperties( + getAnalyticsParams( + signatureRequest as SignatureRequest, + isSimulationEnabled, + ), + ) .build(), ); }, - [chainId, isSimulationEnabled, messageParams, type, signatureRequest], + [isSimulationEnabled, type, signatureRequest], ); useEffect(() => { From fb054d7c30ba8c68a66b3b6073f3d35c3206c6cd Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:01:24 -0800 Subject: [PATCH 16/17] fix: lint unused Hex import --- app/components/Views/confirmations/hooks/useSignatureMetrics.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/Views/confirmations/hooks/useSignatureMetrics.ts b/app/components/Views/confirmations/hooks/useSignatureMetrics.ts index 165d079afcf..f0b5657dade 100644 --- a/app/components/Views/confirmations/hooks/useSignatureMetrics.ts +++ b/app/components/Views/confirmations/hooks/useSignatureMetrics.ts @@ -1,5 +1,4 @@ import { useCallback, useEffect } from 'react'; -import type { Hex } from '@metamask/utils'; import getDecimalChainId from '../../../../util/networks/getDecimalChainId'; import { MetricsEventBuilder } from '../../../../core/Analytics/MetricsEventBuilder'; From 70ed95e5f1bc0ba2b68af93513d202c2d0c3e0ff Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:00:12 -0800 Subject: [PATCH 17/17] fix: utils/signature test --- .../Views/confirmations/utils/signature.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/components/Views/confirmations/utils/signature.test.ts b/app/components/Views/confirmations/utils/signature.test.ts index 08472ef3f27..1b0a8b5cb39 100644 --- a/app/components/Views/confirmations/utils/signature.test.ts +++ b/app/components/Views/confirmations/utils/signature.test.ts @@ -1,6 +1,6 @@ import { parseTypedDataMessage, isRecognizedPermit } from './signature'; import { PRIMARY_TYPES_PERMIT } from '../constants/signatures'; -import { SignatureRequest } from '@metamask/signature-controller'; +import { SignatureRequest, SignatureRequestType } from '@metamask/signature-controller'; describe('Signature Utils', () => { describe('parseTypedDataMessage', () => { @@ -51,7 +51,8 @@ describe('Signature Utils', () => { data: JSON.stringify({ primaryType: PRIMARY_TYPES_PERMIT[0] }) - } + }, + type: SignatureRequestType.TypedSign } as SignatureRequest; expect(isRecognizedPermit(mockRequest)).toBe(true); @@ -63,7 +64,8 @@ describe('Signature Utils', () => { data: JSON.stringify({ primaryType: 'UnrecognizedType' }) - } + }, + type: SignatureRequestType.TypedSign } as SignatureRequest; expect(isRecognizedPermit(mockRequest)).toBe(false);