Skip to content

Commit

Permalink
[IMPROVEMENT] Refactor Personal Signature (#5551)
Browse files Browse the repository at this point in the history
* personal signature refactor
  • Loading branch information
blackdevelopa authored Jan 27, 2023
1 parent bf81d9b commit 74ed06d
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 283 deletions.
1 change: 0 additions & 1 deletion app/components/Nav/Main/RootRPCMethodsUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ const RootRPCMethodsUI = (props) => {
>
{signType === 'personal' && (
<PersonalSign
navigation={props.navigation}
messageParams={signMessageParams}
onCancel={onSignAction}
onConfirm={onSignAction}
Expand Down
212 changes: 212 additions & 0 deletions app/components/UI/PersonalSign/PersonalSign.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import React, { useState, useEffect, useCallback } from 'react';
import { View, Text, InteractionManager } from 'react-native';
import Engine from '../../../core/Engine';
import SignatureRequest from '../SignatureRequest';
import ExpandedMessage from '../SignatureRequest/ExpandedMessage';
import { hexToText } from '@metamask/controller-utils';
import NotificationManager from '../../../core/NotificationManager';
import { strings } from '../../../../locales/i18n';
import { WALLET_CONNECT_ORIGIN } from '../../../util/walletconnect';
import { useSelector } from 'react-redux';
import { MetaMetricsEvents } from '../../../core/Analytics';
import AnalyticsV2 from '../../../util/analyticsV2';
import { getAddressAccountType } from '../../../util/address';
import { KEYSTONE_TX_CANCELED } from '../../../constants/error';
import { MM_SDK_REMOTE_ORIGIN } from '../../../core/SDKConnect';
import { useTheme } from '../../../util/theme';
import { PersonalSignProps } from './types';
import { useNavigation } from '@react-navigation/native';
import createStyles from './styles';

/**
* Component that supports personal_sign
*/
const PersonalSign = ({
onCancel,
onConfirm,
messageParams,
currentPageInformation,
toggleExpandedMessage,
showExpandedMessage,
}: PersonalSignProps) => {
const navigation = useNavigation();
const [truncateMessage, setTruncateMessage] = useState<boolean>(false);

const selectedAddress = useSelector(
(state: any) =>
state.engine.backgroundState.PreferencesController.selectedAddress,
);

const { colors }: any = useTheme();
const styles = createStyles(colors);

interface AnalyticsParams {
account_type?: string;
dapp_host_name?: string;
dapp_url?: string;
chain_id?: string;
sign_type?: string;
[key: string]: string | undefined;
}

const getAnalyticsParams = useCallback((): AnalyticsParams => {
try {
const { NetworkController }: any = Engine.context;
const { chainId } = NetworkController?.state?.provider || {};
const url = new URL(currentPageInformation?.url);

return {
account_type: getAddressAccountType(selectedAddress),
dapp_host_name: url?.host,
dapp_url: currentPageInformation?.url,
chain_id: chainId,
sign_type: 'personal',
...currentPageInformation?.analytics,
};
} catch (error) {
return {};
}
}, [currentPageInformation, selectedAddress]);

useEffect(() => {
AnalyticsV2.trackEvent(
MetaMetricsEvents.SIGN_REQUEST_STARTED,
getAnalyticsParams(),
);
}, [getAnalyticsParams]);

const showWalletConnectNotification = (confirmation = false) => {
InteractionManager.runAfterInteractions(() => {
messageParams.origin &&
(messageParams.origin.startsWith(WALLET_CONNECT_ORIGIN) ||
messageParams.origin.startsWith(MM_SDK_REMOTE_ORIGIN)) &&
NotificationManager.showSimpleNotification({
status: `simple_notification${!confirmation ? '_rejected' : ''}`,
duration: 5000,
title: confirmation
? strings('notifications.wc_signed_title')
: strings('notifications.wc_signed_rejected_title'),
description: strings('notifications.wc_description'),
});
});
};

const signMessage = async () => {
const { KeyringController, PersonalMessageManager }: any = Engine.context;
const messageId = messageParams.metamaskId;
const cleanMessageParams = await PersonalMessageManager.approveMessage(
messageParams,
);
const rawSig = await KeyringController.signPersonalMessage(
cleanMessageParams,
);
PersonalMessageManager.setMessageStatusSigned(messageId, rawSig);
showWalletConnectNotification(true);
};

const rejectMessage = () => {
const { PersonalMessageManager }: any = Engine.context;
const messageId = messageParams.metamaskId;
PersonalMessageManager.rejectMessage(messageId);
showWalletConnectNotification(false);
};

const cancelSignature = () => {
rejectMessage();
AnalyticsV2.trackEvent(
MetaMetricsEvents.SIGN_REQUEST_CANCELLED,
getAnalyticsParams(),
);
onCancel();
};

const confirmSignature = async () => {
try {
await signMessage();
AnalyticsV2.trackEvent(
MetaMetricsEvents.SIGN_REQUEST_COMPLETED,
getAnalyticsParams(),
);
onConfirm();
} catch (e: any) {
if (e?.message.startsWith(KEYSTONE_TX_CANCELED)) {
AnalyticsV2.trackEvent(
MetaMetricsEvents.QR_HARDWARE_TRANSACTION_CANCELED,
getAnalyticsParams(),
);
onCancel();
}
}
};

const shouldTruncateMessage = (e: any) => {
if (e.nativeEvent.lines.length > 5) {
setTruncateMessage(true);
return;
}
setTruncateMessage(false);
};

const renderMessageText = () => {
const textChild = hexToText(messageParams.data)
.split('\n')
.map((line, i) => (
<Text
key={`txt_${i}`}
style={[
styles.messageText,
!showExpandedMessage ? styles.textLeft : null,
]}
>
{line}
{!showExpandedMessage && '\n'}
</Text>
));
let messageText;
if (showExpandedMessage) {
messageText = textChild;
} else {
messageText = truncateMessage ? (
<Text
style={styles.messageTextColor}
numberOfLines={5}
ellipsizeMode={'tail'}
>
{textChild}
</Text>
) : (
<Text
style={styles.messageTextColor}
onTextLayout={shouldTruncateMessage}
>
{textChild}
</Text>
);
}
return messageText;
};

const rootView = showExpandedMessage ? (
<ExpandedMessage
currentPageInformation={currentPageInformation}
renderMessage={renderMessageText}
toggleExpandedMessage={toggleExpandedMessage}
/>
) : (
<SignatureRequest
navigation={navigation}
onCancel={cancelSignature}
onConfirm={confirmSignature}
currentPageInformation={currentPageInformation}
showExpandedMessage={showExpandedMessage}
toggleExpandedMessage={toggleExpandedMessage}
truncateMessage={truncateMessage}
type="personalSign"
>
<View style={styles.messageWrapper}>{renderMessageText()}</View>
</SignatureRequest>
);
return rootView;
};

export default PersonalSign;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`PersonalSign should render correctly 1`] = `
<Connect(PersonalSign)
<PersonalSign
currentPageInformation={
Object {
"title": "title",
Expand All @@ -11,7 +11,13 @@ exports[`PersonalSign should render correctly 1`] = `
messageParams={
Object {
"data": "message",
"from": "0x0",
"metamaskId": "id",
"origin": "origin",
}
}
onCancel={[Function]}
onConfirm={[Function]}
selectedAddress="0x0"
/>
`;
Loading

0 comments on commit 74ed06d

Please sign in to comment.