diff --git a/.eslintrc.js b/.eslintrc.js index 70565eb49450..5d143abed951 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -77,7 +77,12 @@ module.exports = { files: [ 'app/components/UI/Name/**/*.{js,ts,tsx}', 'app/components/UI/SimulationDetails/**/*.{js,ts,tsx}', - 'app/components/hooks/DisplayName/**/*.{js,ts,tsx}' + 'app/components/hooks/DisplayName/**/*.{js,ts,tsx}', + 'app/components/Views/confirmations/components/Confirm/DataTree/**/*.{js,ts,tsx}', + 'app/components/Views/confirmations/components/Confirm/Info/**/*.{js,ts,tsx}', + 'app/components/Views/confirmations/components/PersonalSign/**/*.{js,ts,tsx}', + 'app/components/Views/confirmations/components/SignatureRequest/**/*.{js,ts,tsx}', + 'app/components/Views/confirmations/components/TypedSign/**/*.{js,ts,tsx}', ], rules: { 'no-restricted-syntax': [ diff --git a/app/components/Views/confirmations/components/Confirm/Info/TypedSignV1/Message.tsx b/app/components/Views/confirmations/components/Confirm/Info/TypedSignV1/Message.tsx index 0b8f7fce26fa..e9468d0e982a 100644 --- a/app/components/Views/confirmations/components/Confirm/Info/TypedSignV1/Message.tsx +++ b/app/components/Views/confirmations/components/Confirm/Info/TypedSignV1/Message.tsx @@ -1,10 +1,7 @@ import React from 'react'; -import { useSelector } from 'react-redux'; - -import { selectChainId } from '../../../../../../../selectors/networkController'; -import useApprovalRequest from '../../../../hooks/useApprovalRequest'; import SignatureMessageSection from '../../SignatureMessageSection'; import DataTree, { DataTreeInput } from '../../DataTree/DataTree'; +import { useSignatureRequest } from '../../../../hooks/useSignatureRequest'; interface TypesSignDataV1 { name: string; @@ -13,10 +10,11 @@ interface TypesSignDataV1 { } const Message = () => { - const { approvalRequest } = useApprovalRequest(); - const chainId = useSelector(selectChainId); + const signatureRequest = useSignatureRequest(); + const chainId = signatureRequest?.chainId as string; - const typedSignData = approvalRequest?.requestData?.data; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const typedSignData = signatureRequest?.messageParams?.data as any; if (!typedSignData) { return null; diff --git a/app/components/Views/confirmations/components/Confirm/Info/TypedSignV3V4/Message.tsx b/app/components/Views/confirmations/components/Confirm/Info/TypedSignV3V4/Message.tsx index 55a3c1d2ef6d..04a1d7122c7e 100644 --- a/app/components/Views/confirmations/components/Confirm/Info/TypedSignV3V4/Message.tsx +++ b/app/components/Views/confirmations/components/Confirm/Info/TypedSignV3V4/Message.tsx @@ -1,15 +1,14 @@ import React from 'react'; import { StyleSheet } from 'react-native'; -import { useSelector } from 'react-redux'; import { strings } from '../../../../../../../../locales/i18n'; -import { selectChainId } from '../../../../../../../selectors/networkController'; -import useApprovalRequest from '../../../../hooks/useApprovalRequest'; import { parseSanitizeTypedDataMessage } from '../../../../utils/signatures'; import InfoRow from '../../../UI/InfoRow'; import DataTree from '../../DataTree'; import SignatureMessageSection from '../../SignatureMessageSection'; import { DataTreeInput } from '../../DataTree/DataTree'; +import { useSignatureRequest } from '../../../../hooks/useSignatureRequest'; +import { Hex } from '@metamask/utils'; const styles = StyleSheet.create({ collpasedInfoRow: { @@ -18,10 +17,12 @@ const styles = StyleSheet.create({ }); const Message = () => { - const { approvalRequest } = useApprovalRequest(); - const chainId = useSelector(selectChainId); + const signatureRequest = useSignatureRequest(); + const chainId = signatureRequest?.chainId as Hex; - const typedSignData = approvalRequest?.requestData?.data; + // Pending alignment of controller types. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const typedSignData = signatureRequest?.messageParams?.data as any; if (!typedSignData) { return null; diff --git a/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx b/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx index ac8a7cfd7d1a..9a71d739877e 100644 --- a/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx +++ b/app/components/Views/confirmations/components/PersonalSign/PersonalSign.tsx @@ -23,13 +23,15 @@ import { PersonalSignProps } from './types'; import { SigningBottomSheetSelectorsIDs } from '../../../../../../e2e/selectors/Browser/SigningBottomSheet.selectors'; import { useMetrics } from '../../../../../components/hooks/useMetrics'; import AppConstants from '../../../../../core/AppConstants'; -import { selectChainId } from '../../../../../selectors/networkController'; -import { store } from '../../../../../store'; import Logger from '../../../../../util/Logger'; import { getBlockaidMetricsParams } from '../../../../../util/blockaid'; import createExternalSignModelNav from '../../../../../util/hardwareWallet/signatureUtils'; import { getDecimalChainId } from '../../../../../util/networks'; import { SecurityAlertResponse } from '../BlockaidBanner/BlockaidBanner.types'; +import { selectSignatureRequestById } from '../../../../../selectors/signatureController'; +import { selectNetworkTypeByChainId } from '../../../../../selectors/networkController'; +import { RootState } from '../../../../../reducers'; +import { Hex } from '@metamask/utils'; /** * Converts a hexadecimal string to a utf8 string. @@ -63,12 +65,23 @@ const PersonalSign = ({ const navigation = useNavigation(); const { trackEvent, createEventBuilder } = useMetrics(); const [truncateMessage, setTruncateMessage] = useState(false); + const { securityAlertResponse } = useSelector( // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any (reduxState: any) => reduxState.signatureRequest, ); + const signatureRequest = useSelector((state: RootState) => + selectSignatureRequestById(state, messageParams.metamaskId), + ); + + const { chainId } = signatureRequest ?? {}; + + const networkType = useSelector((state: RootState) => + selectNetworkTypeByChainId(state, chainId as Hex), + ); + // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any const { colors }: any = useTheme(); @@ -84,8 +97,6 @@ const PersonalSign = ({ const getAnalyticsParams = useCallback((): AnalyticsParams => { const pageInfo = currentPageInformation || messageParams.meta || {}; - - const chainId = selectChainId(store.getState()); const fallbackUrl = 'N/A'; let urlHost = fallbackUrl; @@ -101,7 +112,7 @@ const PersonalSign = ({ let blockaidParams: Record = {}; if (securityAlertResponse) { blockaidParams = getBlockaidMetricsParams( - securityAlertResponse as SecurityAlertResponse, + securityAlertResponse as unknown as SecurityAlertResponse, ); } @@ -113,7 +124,7 @@ const PersonalSign = ({ ...pageInfo.analytics, ...blockaidParams, }; - }, [currentPageInformation, messageParams, securityAlertResponse]); + }, [chainId, currentPageInformation, messageParams, securityAlertResponse]); useEffect(() => { const onSignatureError = ({ error }: { error: Error }) => { @@ -259,6 +270,7 @@ const PersonalSign = ({ fromAddress={messageParams.from} origin={messageParams.origin} testID={SigningBottomSheetSelectorsIDs.PERSONAL_REQUEST} + networkType={networkType} > {renderMessageText()} diff --git a/app/components/Views/confirmations/components/PersonalSign/index.test.tsx b/app/components/Views/confirmations/components/PersonalSign/index.test.tsx index dae588716ff6..e04fdfb1942f 100644 --- a/app/components/Views/confirmations/components/PersonalSign/index.test.tsx +++ b/app/components/Views/confirmations/components/PersonalSign/index.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import PersonalSign from '.'; import configureMockStore from 'redux-mock-store'; -import { Provider } from 'react-redux'; +import { Provider, useSelector } from 'react-redux'; import { WALLET_CONNECT_ORIGIN } from '../../../../../util/walletconnect'; import SignatureRequest from '../SignatureRequest'; import Engine from '../../../../../core/Engine'; @@ -12,6 +12,7 @@ import AppConstants from '../../../../../core/AppConstants'; import { strings } from '../../../../../../locales/i18n'; import { backgroundState } from '../../../../../util/test/initial-root-state'; import { useMetrics } from '../../../../../components/hooks/useMetrics'; +import initialBackgroundState from '../../../../../util/test/initial-background-state.json'; jest.mock('../../../../../components/hooks/useMetrics'); jest.mock('../../../../../core/Engine', () => ({ @@ -61,20 +62,7 @@ const store = mockStore(initialState); jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - useSelector: (callback: any) => - callback({ - signatureRequest: { - securityAlertResponse: { - description: '', - features: [], - providerRequestsCount: { eth_chainId: 1 }, - reason: '', - result_type: 'Benign', - }, - }, - }), + useSelector: jest.fn(), })); jest.mock('../../../../../util/address', () => ({ @@ -117,6 +105,51 @@ function createWrapper({ } describe('PersonalSign', () => { + const useSelectorMock = jest.mocked(useSelector); + + beforeEach(() => { + useSelectorMock.mockReset(); + + useSelectorMock.mockImplementationOnce((callback) => + callback({ + signatureRequest: { + securityAlertResponse: { + description: '', + features: [], + providerRequestsCount: { eth_chainId: 1 }, + reason: '', + result_type: 'Benign', + }, + }, + }), + ); + + useSelectorMock.mockImplementationOnce((callback) => + callback({ + engine: { + backgroundState: { + SignatureController: { + signatureRequests: { + [messageParamsMock.metamaskId]: { + chainId: '1', + messageParams: messageParamsMock, + }, + }, + }, + }, + }, + }), + ); + + useSelectorMock.mockImplementationOnce((callback) => + callback({ + engine: { + backgroundState: initialBackgroundState, + }, + }), + ); + }); + it('should render correctly', () => { const wrapper = createWrapper(); expect(wrapper).toMatchSnapshot(); diff --git a/app/components/Views/confirmations/components/SignatureRequest/index.js b/app/components/Views/confirmations/components/SignatureRequest/index.js index 033c92d342b8..9ba8a8eaf0cc 100644 --- a/app/components/Views/confirmations/components/SignatureRequest/index.js +++ b/app/components/Views/confirmations/components/SignatureRequest/index.js @@ -9,7 +9,6 @@ import { withMetricsAwareness } from '../../../../../components/hooks/useMetrics import ExtendedKeyringTypes from '../../../../../constants/keyringTypes'; import { MetaMetricsEvents } from '../../../../../core/Analytics'; import { selectSelectedInternalAccountFormattedAddress } from '../../../../../selectors/accountsController'; -import { selectProviderType } from '../../../../../selectors/networkController'; import { fontStyles } from '../../../../../styles/common'; import { isHardwareAccount } from '../../../../../util/address'; import { getAnalyticsParams } from '../../../../../util/confirmation/signatureUtils'; @@ -149,7 +148,7 @@ class SignatureRequest extends PureComponent { */ type: PropTypes.string, /** - * String representing the selected network + * String representing the associated network */ networkType: PropTypes.string, /** @@ -401,7 +400,6 @@ class SignatureRequest extends PureComponent { const mapStateToProps = (state) => ({ selectedAddress: selectSelectedInternalAccountFormattedAddress(state), - networkType: selectProviderType(state), securityAlertResponse: state.signatureRequest.securityAlertResponse, }); diff --git a/app/components/Views/confirmations/components/TypedSign/index.js b/app/components/Views/confirmations/components/TypedSign/index.js index 036dd62fb612..fd802b80ec1f 100644 --- a/app/components/Views/confirmations/components/TypedSign/index.js +++ b/app/components/Views/confirmations/components/TypedSign/index.js @@ -28,6 +28,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 { selectNetworkTypeByChainId } from '../../../../../selectors/networkController'; +import { selectSignatureRequestById } from '../../../../../selectors/signatureController'; const createStyles = (colors) => StyleSheet.create({ @@ -95,6 +97,10 @@ class TypedSign extends PureComponent { * Metrics injected by withMetricsAwareness HOC */ metrics: PropTypes.object, + /** + * String representing the associated network + */ + networkType: PropTypes.string, }; state = { @@ -242,6 +248,7 @@ class TypedSign extends PureComponent { showExpandedMessage, toggleExpandedMessage, messageParams: { from }, + networkType } = this.props; const { truncateMessage } = this.state; const messageWrapperStyles = []; @@ -251,6 +258,7 @@ class TypedSign extends PureComponent { if (messageParams.version === 'V3') { domain = JSON.parse(messageParams.data).domain; } + if (truncateMessage) { messageWrapperStyles.push(styles.truncatedMessageWrapper); if (Device.isIos()) { @@ -278,6 +286,7 @@ class TypedSign extends PureComponent { type={typedSign[messageParams.version]} fromAddress={from} testID={SigningBottomSheetSelectorsIDs.TYPED_REQUEST} + networkType={networkType} > ({ - securityAlertResponse: state.signatureRequest.securityAlertResponse, -}); +const mapStateToProps = (state, ownProps) => { + const signatureRequest = selectSignatureRequestById(state, ownProps.messageParams.metamaskId); + + return { + networkType: selectNetworkTypeByChainId(state, signatureRequest?.chainId), + securityAlertResponse: state.signatureRequest.securityAlertResponse, + }; +}; export default connect(mapStateToProps)(withMetricsAwareness(TypedSign)); diff --git a/app/components/Views/confirmations/hooks/useSignatureRequest.test.ts b/app/components/Views/confirmations/hooks/useSignatureRequest.test.ts new file mode 100644 index 000000000000..716bc4a25fee --- /dev/null +++ b/app/components/Views/confirmations/hooks/useSignatureRequest.test.ts @@ -0,0 +1,73 @@ +import { + SignatureRequest, + SignatureRequestType, +} from '@metamask/signature-controller'; +import { renderHookWithProvider } from '../../../../util/test/renderWithProvider'; +import { useSignatureRequest } from './useSignatureRequest'; +import { ApprovalType } from '@metamask/controller-utils'; + +const ID_MOCK = '123-456-789'; + +const SIGNATURE_REQUEST_MOCK: Partial = { + id: ID_MOCK, + messageParams: { + data: '0xdata', + from: '0xfrom', + origin: 'https://origin.com', + }, + type: SignatureRequestType.PersonalSign, +}; + +function renderHook({ + approvalType, + signatureRequest, +}: { + approvalType?: ApprovalType; + signatureRequest: Partial; +}) { + const { result } = renderHookWithProvider(useSignatureRequest, { + state: { + engine: { + backgroundState: { + ApprovalController: { + pendingApprovals: { + [ID_MOCK]: { + id: ID_MOCK, + type: approvalType ?? ApprovalType.PersonalSign, + }, + }, + }, + SignatureController: { + signatureRequests: { + [signatureRequest.id as string]: signatureRequest, + }, + }, + }, + }, + }, + }); + + return result.current; +} + +describe('useSignatureRequest', () => { + it('returns signature request matching approval request ID', () => { + const result = renderHook({ signatureRequest: SIGNATURE_REQUEST_MOCK }); + expect(result).toStrictEqual(SIGNATURE_REQUEST_MOCK); + }); + + it('returns undefined if matching signature request not found', () => { + const result = renderHook({ + signatureRequest: { ...SIGNATURE_REQUEST_MOCK, id: 'invalid-id' }, + }); + expect(result).toBeUndefined(); + }); + + it('returns undefined if wrong approval type', () => { + const result = renderHook({ + signatureRequest: SIGNATURE_REQUEST_MOCK, + approvalType: ApprovalType.Transaction, + }); + expect(result).toBeUndefined(); + }); +}); diff --git a/app/components/Views/confirmations/hooks/useSignatureRequest.ts b/app/components/Views/confirmations/hooks/useSignatureRequest.ts new file mode 100644 index 000000000000..88c530d08425 --- /dev/null +++ b/app/components/Views/confirmations/hooks/useSignatureRequest.ts @@ -0,0 +1,27 @@ +import { useSelector } from 'react-redux'; +import useApprovalRequest from './useApprovalRequest'; +import { ApprovalType } from '@metamask/controller-utils'; +import { selectSignatureRequestById } from '../../../../selectors/signatureController'; +import { RootState } from '../../../UI/BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal.test'; + +const SIGNATURE_APPROVAL_TYPES = [ + ApprovalType.PersonalSign, + ApprovalType.EthSignTypedData, +]; + +export function useSignatureRequest() { + const { approvalRequest } = useApprovalRequest(); + + const signatureRequest = useSelector((state: RootState) => + selectSignatureRequestById(state, approvalRequest?.id as string), + ); + + if ( + !SIGNATURE_APPROVAL_TYPES.includes(approvalRequest?.type as ApprovalType) || + !signatureRequest + ) { + return undefined; + } + + return signatureRequest; +} diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index 83738466d728..9759da68339a 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -2099,6 +2099,7 @@ export default { ApprovalController, LoggingController, AccountsController, + SignatureController, } = instance.datamodel.state; return { @@ -2133,6 +2134,7 @@ export default { ApprovalController, LoggingController, AccountsController, + SignatureController, }; }, diff --git a/app/core/Engine/types.ts b/app/core/Engine/types.ts index 7484b425db73..7153b4a4ff07 100644 --- a/app/core/Engine/types.ts +++ b/app/core/Engine/types.ts @@ -136,6 +136,7 @@ import { SignatureController, SignatureControllerActions, SignatureControllerEvents, + SignatureControllerState, } from '@metamask/signature-controller'; import SmartTransactionsController, { type SmartTransactionsControllerActions, @@ -382,4 +383,5 @@ export type EngineState = { PPOMController: PPOMState; AccountsController: AccountsControllerState; SelectedNetworkController: SelectedNetworkControllerState; + SignatureController: SignatureControllerState; }; diff --git a/app/selectors/networkController.ts b/app/selectors/networkController.ts index cb18e5e4deb1..9f09838ab967 100644 --- a/app/selectors/networkController.ts +++ b/app/selectors/networkController.ts @@ -53,6 +53,11 @@ const getDefaultProviderConfig = (): ProviderConfig => ({ type: RpcEndpointType.Infura, }); +const getNetworkType = (rpcEndpoint: RpcEndpoint): string => + rpcEndpoint.type === RpcEndpointType.Custom + ? 'rpc' + : rpcEndpoint.networkClientId; + // Helper function to create the provider config based on the network and endpoint export const createProviderConfig = ( networkConfig: NetworkConfiguration, @@ -72,10 +77,7 @@ export const createProviderConfig = ( chainId, ticker: nativeCurrency, rpcPrefs: { ...(blockExplorerUrl && { blockExplorerUrl }) }, - type: - rpcEndpoint.type === RpcEndpointType.Custom - ? 'rpc' - : rpcEndpoint.networkClientId, + type: getNetworkType(rpcEndpoint), ...(rpcEndpoint.type === RpcEndpointType.Custom && { id: rpcEndpoint.networkClientId, nickname: name, @@ -224,3 +226,20 @@ export const selectNativeCurrencyByChainId = createSelector( (networkConfigurations, chainId) => networkConfigurations?.[chainId]?.nativeCurrency, ); + +export const selectDefaultEndpointByChainId = createSelector( + selectNetworkConfigurations, + (_: RootState, chainId: Hex) => chainId, + (networkConfigurations, chainId) => { + const networkConfiguration = networkConfigurations[chainId as Hex]; + return networkConfiguration?.rpcEndpoints?.[ + networkConfiguration.defaultRpcEndpointIndex + ]; + }, +); + +export const selectNetworkTypeByChainId = createSelector( + selectDefaultEndpointByChainId, + (defaultEndpoint) => + defaultEndpoint ? getNetworkType(defaultEndpoint) : undefined, +); diff --git a/app/selectors/signatureController.ts b/app/selectors/signatureController.ts new file mode 100644 index 000000000000..8d9ba0f9ead2 --- /dev/null +++ b/app/selectors/signatureController.ts @@ -0,0 +1,18 @@ +import { SignatureRequest } from '@metamask/signature-controller'; +import { RootState } from '../reducers'; +import { createDeepEqualSelector } from './util'; + +const selectSignatureControllerState = (state: RootState) => + state.engine.backgroundState.SignatureController; + +export const selectSignatureRequests = createDeepEqualSelector( + (state: RootState) => selectSignatureControllerState(state).signatureRequests, + (signatureRequests) => signatureRequests as Record, +); + +export const selectSignatureRequestById = createDeepEqualSelector( + selectSignatureRequests, + (_: RootState, id: string) => id, + (signatureRequests, id) => + signatureRequests[id] as SignatureRequest | undefined, +); diff --git a/app/util/test/confirm-data-helpers.ts b/app/util/test/confirm-data-helpers.ts index 3d002d6bb270..ec6d4f1f3197 100644 --- a/app/util/test/confirm-data-helpers.ts +++ b/app/util/test/confirm-data-helpers.ts @@ -1,4 +1,6 @@ +import { MessageParamsTyped } from '@metamask/signature-controller'; import { backgroundState } from './initial-root-state'; +import { Hex } from '@metamask/utils'; export const personalSignatureConfirmationState = { engine: { @@ -59,7 +61,7 @@ export const typedSignV1ConfirmationState = { analytics: { request_source: 'In-App-Browser' }, }, origin: 'metamask.github.io', - metamaskId: '7e62bcb0-a4e9-11ef-9b51-ddf21c91a998', + metamaskId: '7e62bcb1-a4e9-11ef-9b51-ddf21c91a998', version: 'V1', }, requestState: null, @@ -69,6 +71,30 @@ export const typedSignV1ConfirmationState = { pendingApprovalCount: 1, approvalFlows: [], }, + SignatureController: { + signatureRequests: { + '7e62bcb1-a4e9-11ef-9b51-ddf21c91a998': { + chainId: '0x1' as Hex, + messageParams: { + data: [ + { type: 'string', name: 'Message', value: 'Hi, Alice!' }, + { type: 'uint32', name: 'A number', value: '1337' }, + ], + from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + requestId: 2453610887, + meta: { + url: 'https://metamask.github.io/test-dapp/', + title: 'E2E Test Dapp', + icon: { uri: 'https://metamask.github.io/metamask-fox.svg' }, + analytics: { request_source: 'In-App-Browser' }, + }, + origin: 'metamask.github.io', + metamaskId: '7e62bcb0-a4e9-11ef-9b51-ddf21c91a998', + version: 'V1', + } as MessageParamsTyped, + }, + }, + }, }, }, }; @@ -127,7 +153,7 @@ export const typedSignV3ConfirmationState = { analytics: { request_source: 'In-App-Browser' }, }, origin: 'metamask.github.io', - metamaskId: 'fb2029e0-b0ab-11ef-9227-05a11087c334', + metamaskId: 'fb2029e1-b0ab-11ef-9227-05a11087c334', version: 'V3', }, requestState: null, @@ -137,6 +163,27 @@ export const typedSignV3ConfirmationState = { pendingApprovalCount: 1, approvalFlows: [], }, + SignatureController: { + signatureRequests: { + 'fb2029e1-b0ab-11ef-9227-05a11087c334': { + chainId: '0x1' as Hex, + messageParams: { + data: JSON.stringify(mockTypedSignV3Message), + from: '0x8eeee1781fd885ff5ddef7789486676961873d12', + requestId: 3298650200, + meta: { + url: 'https://metamask.github.io/test-dapp/', + title: 'E2E Test Dapp', + icon: { uri: 'https://metamask.github.io/metamask-fox.svg' }, + analytics: { request_source: 'In-App-Browser' }, + }, + origin: 'metamask.github.io', + metamaskId: 'fb2029e1-b0ab-11ef-9227-05a11087c334', + version: 'V3', + } as MessageParamsTyped, + }, + }, + }, }, }, };