Skip to content

Commit

Permalink
feat: adding basic page for typed signatures V3, V4 (MetaMask#12506)
Browse files Browse the repository at this point in the history
## **Description**

Adding basic page for types sign V3, V4.

## **Related issues**

Fixes: MetaMask/MetaMask-planning#3681

## **Manual testing steps**

1. Enable re-designs locally
2. To to test dapp and submit V3, V4 signatures
3. Check the page that appears

## **Screenshots/Recordings**
<img width="391" alt="Screenshot 2024-12-02 at 5 16 06 PM"
src="https://github.com/user-attachments/assets/f198a928-70f9-48a9-ae93-2029b9ae3480">

## **Pre-merge author checklist**

- [X] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I’ve included tests if applicable
- [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
jpuri authored Dec 12, 2024
1 parent 2f0cc61 commit caae9fa
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import React from 'react';
import useApprovalRequest from '../../../hooks/useApprovalRequest';
import PersonalSign from './PersonalSign';
import TypedSignV1 from './TypedSignV1';
import TypedSignV3V4 from './TypedSignV3V4';

const ConfirmationInfoComponentMap = {
[TransactionType.personalSign]: () => PersonalSign,
[TransactionType.signTypedData]: () => TypedSignV1,
[TransactionType.signTypedData]: (approvalRequestVersion: string) => {
if (approvalRequestVersion === 'V1') return TypedSignV1;
return TypedSignV3V4;
},
};

const Info = () => {
Expand All @@ -17,10 +21,14 @@ const Info = () => {
return null;
}

const InfoComponent: React.FC =
ConfirmationInfoComponentMap[
approvalRequest?.type as keyof typeof ConfirmationInfoComponentMap
]();
const { requestData } = approvalRequest ?? {
requestData: {},
};
const approvalRequestVersion = requestData?.version;

const InfoComponent: React.FC = ConfirmationInfoComponentMap[
approvalRequest?.type as keyof typeof ConfirmationInfoComponentMap
](approvalRequestVersion);

return <InfoComponent />;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React from 'react';

import { strings } from '../../../../../../../../locales/i18n';
import useApprovalRequest from '../../../../hooks/useApprovalRequest';
import InfoSection from '../../../UI/InfoRow/InfoSection';
import InfoRow from '../../../UI/InfoRow';
import DisplayURL from '../../../UI/InfoRow/InfoValue/DisplayURL';
import NoChangeSimulation from '../../NoChangeSimulation';
import InfoRowOrigin from '../Shared/InfoRowOrigin';
import Message from './Message';

const PersonalSign = () => {
Expand All @@ -18,14 +15,7 @@ const PersonalSign = () => {
return (
<>
<NoChangeSimulation />
<InfoSection>
<InfoRow
label={strings('confirm.request_from')}
tooltip={strings('confirm.personal_sign_tooltip')}
>
<DisplayURL url={approvalRequest.origin} />
</InfoRow>
</InfoSection>
<InfoRowOrigin />
<Message />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

import renderWithProvider from '../../../../../../../../util/test/renderWithProvider';
import { typedSignV1ConfirmationState } from '../../../../../../../../util/test/confirm-data-helpers';
import InfoRowOrigin from './InfoRowOrigin';

describe('InfoRowOrigin', () => {
it('should contained required text', async () => {
const { getByText } = renderWithProvider(<InfoRowOrigin />, {
state: typedSignV1ConfirmationState,
});
expect(getByText('Request from')).toBeDefined();
expect(getByText('metamask.github.io')).toBeDefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

import { strings } from '../../../../../../../../../locales/i18n';
import useApprovalRequest from '../../../../../hooks/useApprovalRequest';
import InfoSection from '../../../../UI/InfoRow/InfoSection';
import InfoRow from '../../../../UI/InfoRow';
import DisplayURL from '../../../../UI/InfoRow/InfoValue/DisplayURL';

const InfoRowOrigin = () => {
const { approvalRequest } = useApprovalRequest();

if (!approvalRequest) {
return null;
}

return (
<InfoSection>
<InfoRow
label={strings('confirm.request_from')}
tooltip={strings('confirm.personal_sign_tooltip')}
>
<DisplayURL url={approvalRequest.origin} />
</InfoRow>
</InfoSection>
);
};

export default InfoRowOrigin;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './InfoRowOrigin';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import renderWithProvider from '../../../../../../../util/test/renderWithProvider';
import { typedSignV1ConfirmationState } from '../../../../../../../util/test/confirm-data-helpers';
import TypedSignV1 from './index';
import TypedSignV1 from './TypedSignV1';

describe('TypedSignV1', () => {
it('should contained required text', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import React from 'react';

import { strings } from '../../../../../../../../locales/i18n';
import useApprovalRequest from '../../../../hooks/useApprovalRequest';
import InfoSection from '../../../UI/InfoRow/InfoSection';
import InfoRow from '../../../UI/InfoRow';
import DisplayURL from '../../../UI/InfoRow/InfoValue/DisplayURL';
import Message from './Message';
import NoChangeSimulation from '../../NoChangeSimulation';
import InfoRowOrigin from '../Shared/InfoRowOrigin';
import Message from './Message';

const TypedSignV1 = () => {
const { approvalRequest } = useApprovalRequest();
Expand All @@ -18,14 +15,7 @@ const TypedSignV1 = () => {
return (
<>
<NoChangeSimulation />
<InfoSection>
<InfoRow
label={strings('confirm.request_from')}
tooltip={strings('confirm.personal_sign_tooltip')}
>
<DisplayURL url={approvalRequest.origin} />
</InfoRow>
</InfoSection>
<InfoRowOrigin />
<Message />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { Text } from 'react-native';

import useApprovalRequest from '../../../../hooks/useApprovalRequest';
import SignatureMessageSection from '../../SignatureMessageSection';

const Message = () => {
const { approvalRequest } = useApprovalRequest();

const typedSignData = approvalRequest?.requestData?.data;

if (!typedSignData) {
return null;
}

const parsedData = JSON.stringify(typedSignData);

const firstDataValue = parsedData?.substring(0, 100);

// todo: detailed data tree to be implemented
return (
<SignatureMessageSection
messageCollapsed={<Text>{firstDataValue}</Text>}
messageExpanded={<Text>{parsedData}</Text>}
copyMessageText={typedSignData}
/>
);
};

export default Message;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

import renderWithProvider from '../../../../../../../util/test/renderWithProvider';
import { typedSignV3ConfirmationState } from '../../../../../../../util/test/confirm-data-helpers';
import TypedSignV1 from './TypedSignV3V4';

describe('TypedSignV3V4', () => {
it('should contained required text', async () => {
const { getByText } = renderWithProvider(<TypedSignV1 />, {
state: typedSignV3ConfirmationState,
});
expect(getByText('Request from')).toBeDefined();
expect(getByText('metamask.github.io')).toBeDefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

import useApprovalRequest from '../../../../hooks/useApprovalRequest';
import InfoRowOrigin from '../Shared/InfoRowOrigin';
import Message from './Message';

const TypedSignV3V4 = () => {
const { approvalRequest } = useApprovalRequest();

if (!approvalRequest) {
return null;
}

return (
<>
{/* SIMULATION TO BE ADDED */}
<InfoRowOrigin />
<Message />
</>
);
};

export default TypedSignV3V4;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './TypedSignV3V4';
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ import useApprovalRequest from './useApprovalRequest';
const useConfirmationRedesignEnabled = () => {
const { approvalRequest } = useApprovalRequest();

const { type: approvalRequestType, requestData } = approvalRequest ?? {
const { type: approvalRequestType } = approvalRequest ?? {
requestData: {},
};
const approvalRequestVersion = requestData?.version;

const isRedesignedEnabled = useMemo(
() =>
approvalRequestType &&
process.env.REDESIGNED_SIGNATURE_REQUEST === 'true' &&
(approvalRequestType === ApprovalTypes.PERSONAL_SIGN ||
(approvalRequestType === ApprovalTypes.ETH_SIGN_TYPED_DATA &&
approvalRequestVersion === 'V1')),
[approvalRequestType, approvalRequestVersion],
[ApprovalTypes.PERSONAL_SIGN, ApprovalTypes.ETH_SIGN_TYPED_DATA].includes(
approvalRequestType as ApprovalTypes,
),
[approvalRequestType],
);

return { isRedesignedEnabled };
Expand Down
36 changes: 36 additions & 0 deletions app/util/test/confirm-data-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,39 @@ export const typedSignV1ConfirmationState = {
},
},
};

export const typedSignV3ConfirmationState = {
engine: {
backgroundState: {
...backgroundState,
ApprovalController: {
pendingApprovals: {
'fb2029e1-b0ab-11ef-9227-05a11087c334': {
id: 'fb2029e1-b0ab-11ef-9227-05a11087c334',
origin: 'metamask.github.io',
type: 'eth_signTypedData',
time: 1733143817088,
requestData: {
data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":1,"verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}',
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: 'fb2029e0-b0ab-11ef-9227-05a11087c334',
version: 'V3',
},
requestState: null,
expectsResult: true,
},
},
pendingApprovalCount: 1,
approvalFlows: [],
},
},
},
};

0 comments on commit caae9fa

Please sign in to comment.