diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 25ad96fce540..4d251becd20a 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -4679,9 +4679,24 @@
"simulationsSettingSubHeader": {
"message": "Estimate balance changes"
},
+ "siweIssued": {
+ "message": "Issued"
+ },
+ "siweNetwork": {
+ "message": "Network"
+ },
+ "siweRequestId": {
+ "message": "Request ID"
+ },
+ "siweResources": {
+ "message": "Resources"
+ },
"siweSignatureSimulationDetailInfo": {
"message": "This type of signature is not able to move your assets and is used for signing in."
},
+ "siweURI": {
+ "message": "URL"
+ },
"skip": {
"message": "Skip"
},
diff --git a/package.json b/package.json
index 41e2dbc4cec4..041520f59739 100644
--- a/package.json
+++ b/package.json
@@ -489,6 +489,7 @@
"@types/gulp-sourcemaps": "^0.0.35",
"@types/he": "^1",
"@types/jest": "^29.5.12",
+ "@types/luxon": "^3.4.2",
"@types/mocha": "^10.0.3",
"@types/node": "^20",
"@types/pify": "^5.0.1",
diff --git a/test/data/confirmations/personal_sign.ts b/test/data/confirmations/personal_sign.ts
index e0c9d093d78c..c6f7907eccc4 100644
--- a/test/data/confirmations/personal_sign.ts
+++ b/test/data/confirmations/personal_sign.ts
@@ -46,3 +46,41 @@ export const signatureRequestSIWE = {
},
},
};
+
+export const SignatureRequestSIWEWithResources = {
+ id: '210ca3b0-1ccb-11ef-b096-89c4d726ebb5',
+ securityAlertResponse: {
+ reason: 'loading',
+ result_type: 'validation_in_progress',
+ securityAlertId: 'b826df20-2eda-41bf-becf-6a100141a8be',
+ },
+ status: 'unapproved',
+ time: 1716884423019,
+ type: 'personal_sign',
+ msgParams: {
+ from: '0x935e73edb9ff52e23bac7f7e049a1ecd06d05477',
+ data: '0x6d6574616d61736b2e6769746875622e696f2077616e747320796f7520746f207369676e20696e207769746820796f757220457468657265756d206163636f756e743a0a3078393335653733656462396666353265323362616337663765303433613165636430366430353437370a0a492061636365707420746865204d6574614d61736b205465726d73206f6620536572766963653a2068747470733a2f2f636f6d6d756e6974792e6d6574616d61736b2e696f2f746f730a0a5552493a2068747470733a2f2f6d6574616d61736b2e6769746875622e696f0a56657273696f6e3a20310a436861696e2049443a20310a4e6f6e63653a2033323839313735370a4973737565642041743a20323032312d30392d33305431363a32353a32342e3030305a',
+ signatureMethod: 'personal_sign',
+ origin: 'https://metamask.github.io',
+ siwe: {
+ isSIWEMessage: true,
+ parsedMessage: {
+ domain: 'metamask.github.io',
+ address: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477',
+ statement:
+ 'I accept the MetaMask Terms of Service: https://community.metamask.io/tos',
+ uri: 'https://metamask.github.io',
+ version: '1',
+ chainId: 1,
+ nonce: '32891757',
+ issuedAt: '2021-09-30T16:25:24.000Z',
+ notBefore: '2022-03-17T12:45:13.610Z',
+ requestId: 'some_id',
+ resources: [
+ 'ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu',
+ 'https://example.com/my-web2-claim.json',
+ ],
+ },
+ },
+ },
+};
diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx
index 2fc34a299182..93e8aff2ef35 100644
--- a/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx
+++ b/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx
@@ -22,6 +22,7 @@ import { SignatureRequestType } from '../../../../types/confirm';
import { selectUseTransactionSimulations } from '../../../../selectors/preferences';
import { isSIWESignatureRequest } from '../../../../utils';
import { AlertRow } from '../../../../../../components/app/confirm/info/row/alert-row/alert-row';
+import { SIWESignInfo } from './siwe-sign';
const PersonalSignInfo: React.FC = () => {
const t = useI18nContext();
@@ -37,11 +38,11 @@ const PersonalSignInfo: React.FC = () => {
}
const { from } = currentConfirmation.msgParams;
- const isSiweSigReq = isSIWESignatureRequest(currentConfirmation);
+ const isSIWE = isSIWESignatureRequest(currentConfirmation);
return (
<>
- {isSiweSigReq && useTransactionSimulations && (
+ {isSIWE && useTransactionSimulations && (
{
>
- {isSiweSigReq && (
+ {isSIWE && (
@@ -82,17 +83,21 @@ const PersonalSignInfo: React.FC = () => {
padding={2}
marginBottom={4}
>
-
-
-
+ {isSIWE ? (
+
+ ) : (
+
+
+
+ )}
>
);
diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/__snapshots__/siwe-sign.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/__snapshots__/siwe-sign.test.tsx.snap
new file mode 100644
index 000000000000..1e62756cf223
--- /dev/null
+++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/__snapshots__/siwe-sign.test.tsx.snap
@@ -0,0 +1,547 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`SIWESignInfo renders correctly for SIWE signature request 1`] = `
+
+
+
+
+
+ I accept the MetaMask Terms of Service: https://community.metamask.io/tos
+
+
+
+
+
+
+
+ metamask.github.io
+
+
+
+
+
+
+
+
+
+
+ 0x935e7...05477
+
+
+
+
+
+
+
+
+
+
+
+ 30 September 2021, 16:25
+
+
+
+
+`;
+
+exports[`SIWESignInfo renders correctly for SIWE signature request with resources 1`] = `
+
+
+
+
+
+ I accept the MetaMask Terms of Service: https://community.metamask.io/tos
+
+
+
+
+
+
+
+ metamask.github.io
+
+
+
+
+
+
+
+
+
+
+ 0x935E7...05477
+
+
+
+
+
+
+
+
+
+
+
+ 30 September 2021, 16:25
+
+
+
+
+
+
+
+
+ ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
+
+
+
+
+ https://example.com/my-web2-claim.json
+
+
+
+
+`;
diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/index.ts b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/index.ts
new file mode 100644
index 000000000000..e62d38d2b793
--- /dev/null
+++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/index.ts
@@ -0,0 +1 @@
+export { default as SIWESignInfo } from './siwe-sign';
diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.stories.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.stories.tsx
new file mode 100644
index 000000000000..8434f23752eb
--- /dev/null
+++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.stories.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Provider } from 'react-redux';
+
+import { SignatureRequestSIWEWithResources } from '../../../../../../../../test/data/confirmations/personal_sign';
+import mockState from '../../../../../../../../test/data/mock-state.json';
+import configureStore from '../../../../../../../store/store';
+
+import SIWESignInfo from './siwe-sign';
+
+const store = configureStore({
+ metamask: {
+ ...mockState.metamask,
+ },
+ confirm: {
+ currentConfirmation: SignatureRequestSIWEWithResources,
+ },
+});
+
+const Story = {
+ title: 'Components/App/Confirm/info/SIWESignInfo',
+ component: SIWESignInfo,
+ decorators: [
+ (story: () => any) => {story()},
+ ],
+};
+
+export default Story;
+
+export const DefaultStory = () => ;
+
+DefaultStory.storyName = 'Default';
diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.test.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.test.tsx
new file mode 100644
index 000000000000..abede6223caa
--- /dev/null
+++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.test.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import configureMockStore from 'redux-mock-store';
+
+import mockState from '../../../../../../../../test/data/mock-state.json';
+import { renderWithProvider } from '../../../../../../../../test/lib/render-helpers';
+import {
+ SignatureRequestSIWEWithResources,
+ signatureRequestSIWE,
+} from '../../../../../../../../test/data/confirmations/personal_sign';
+import SIWESignInfo from './siwe-sign';
+
+describe('SIWESignInfo', () => {
+ it('renders correctly for SIWE signature request', () => {
+ const state = {
+ ...mockState,
+ confirm: {
+ currentConfirmation: signatureRequestSIWE,
+ },
+ };
+ const mockStore = configureMockStore([])(state);
+ const { container } = renderWithProvider(, mockStore);
+ expect(container).toMatchSnapshot();
+ });
+
+ it('renders correctly for SIWE signature request with resources', () => {
+ const state = {
+ ...mockState,
+ confirm: {
+ currentConfirmation: SignatureRequestSIWEWithResources,
+ },
+ };
+ const mockStore = configureMockStore([])(state);
+ const { container } = renderWithProvider(, mockStore);
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx
new file mode 100644
index 000000000000..8c1260c3ede5
--- /dev/null
+++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx
@@ -0,0 +1,85 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { toHex } from '@metamask/controller-utils';
+
+import { NETWORK_TO_NAME_MAP } from '../../../../../../../../shared/constants/network';
+import { useI18nContext } from '../../../../../../../hooks/useI18nContext';
+import { currentConfirmationSelector } from '../../../../../../../selectors';
+import { SignatureRequestType } from '../../../../../types/confirm';
+import {
+ ConfirmInfoRow,
+ ConfirmInfoRowAddress,
+ ConfirmInfoRowText,
+} from '../../../../../../../components/app/confirm/info/row';
+import { formatDate } from '../../../../../utils/date';
+
+const SIWESignInfo: React.FC = () => {
+ const t = useI18nContext();
+ const currentConfirmation = useSelector(
+ currentConfirmationSelector,
+ ) as SignatureRequestType;
+
+ const siweMessage = currentConfirmation?.msgParams?.siwe?.parsedMessage;
+
+ if (!siweMessage) {
+ return null;
+ }
+
+ const {
+ address,
+ chainId,
+ domain,
+ issuedAt,
+ nonce,
+ requestId,
+ statement,
+ resources,
+ version,
+ } = siweMessage;
+ const hexChainId = toHex(chainId);
+ const network =
+ (NETWORK_TO_NAME_MAP as Record)[hexChainId] ?? hexChainId;
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {requestId && (
+
+
+
+ )}
+ {resources && (
+
+ {resources.map((resource, index) => (
+
+ ))}
+
+ )}
+ >
+ );
+};
+
+export default SIWESignInfo;
diff --git a/ui/pages/confirmations/components/confirm/utils.test.ts b/ui/pages/confirmations/components/confirm/utils.test.ts
index 2250d62fa62c..87e6307de7be 100644
--- a/ui/pages/confirmations/components/confirm/utils.test.ts
+++ b/ui/pages/confirmations/components/confirm/utils.test.ts
@@ -20,9 +20,9 @@ describe('getConfirmationSender()', () => {
});
test("returns the sender address from a transaction if it's passed", () => {
- const testCurrentConfirmation =
- unapprovedPersonalSignMsg as SignatureRequestType;
- const { from } = getConfirmationSender(testCurrentConfirmation);
+ const { from } = getConfirmationSender(
+ unapprovedPersonalSignMsg as SignatureRequestType,
+ );
expect(from).toEqual(PERSONAL_SIGN_SENDER_ADDRESS);
});
diff --git a/ui/pages/confirmations/types/confirm.ts b/ui/pages/confirmations/types/confirm.ts
index 70e173b03deb..a48e1d4984ba 100644
--- a/ui/pages/confirmations/types/confirm.ts
+++ b/ui/pages/confirmations/types/confirm.ts
@@ -28,6 +28,18 @@ export type SignatureRequestType = {
version?: string;
siwe?: {
isSIWEMessage: boolean;
+ parsedMessage: null | {
+ domain: string;
+ address: string;
+ statement: string;
+ uri: string;
+ version: string;
+ chainId: number;
+ nonce: string;
+ issuedAt: string;
+ requestId?: string;
+ resources?: string[];
+ };
};
};
type: TransactionType;
diff --git a/ui/pages/confirmations/utils/date.test.ts b/ui/pages/confirmations/utils/date.test.ts
new file mode 100644
index 000000000000..dc1fdd40454a
--- /dev/null
+++ b/ui/pages/confirmations/utils/date.test.ts
@@ -0,0 +1,15 @@
+import { formatDate } from './date';
+
+describe('date util', () => {
+ describe('formatDate', () => {
+ it('formats passed date string', () => {
+ expect(formatDate('2021-09-30T16:25:24.000Z')).toEqual(
+ '30 September 2021, 16:25',
+ );
+ });
+
+ it('returns empty string if empty string is passed', () => {
+ expect(formatDate('')).toEqual('');
+ });
+ });
+});
diff --git a/ui/pages/confirmations/utils/date.ts b/ui/pages/confirmations/utils/date.ts
new file mode 100644
index 000000000000..19ffa5d027d4
--- /dev/null
+++ b/ui/pages/confirmations/utils/date.ts
@@ -0,0 +1,12 @@
+import { DateTime } from 'luxon';
+
+export const formatDate = (dateString: string) => {
+ if (!dateString) {
+ return dateString;
+ }
+
+ return DateTime.fromISO(dateString)
+ .setLocale('en')
+ .setZone('utc')
+ .toFormat('dd LLLL yyyy, HH:mm');
+};
diff --git a/yarn.lock b/yarn.lock
index 5f7759c93188..f5cd2d65be86 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9950,6 +9950,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/luxon@npm:^3.4.2":
+ version: 3.4.2
+ resolution: "@types/luxon@npm:3.4.2"
+ checksum: 10/fd89566e3026559f2bc4ddcc1e70a2c16161905ed50be9473ec0cfbbbe919165041408c4f6e06c4bcf095445535052e2c099087c76b1b38e368127e618fc968d
+ languageName: node
+ linkType: hard
+
"@types/mdast@npm:^3.0.0":
version: 3.0.10
resolution: "@types/mdast@npm:3.0.10"
@@ -25023,6 +25030,7 @@ __metadata:
"@types/gulp-sourcemaps": "npm:^0.0.35"
"@types/he": "npm:^1"
"@types/jest": "npm:^29.5.12"
+ "@types/luxon": "npm:^3.4.2"
"@types/mocha": "npm:^10.0.3"
"@types/node": "npm:^20"
"@types/pify": "npm:^5.0.1"