diff --git a/app/components/Views/confirmations/components/info/personal-sign/message.tsx b/app/components/Views/confirmations/components/info/personal-sign/message.tsx
index 82223fa2bfb1..a61d6223cced 100644
--- a/app/components/Views/confirmations/components/info/personal-sign/message.tsx
+++ b/app/components/Views/confirmations/components/info/personal-sign/message.tsx
@@ -8,7 +8,7 @@ import Text from '../../../../../../component-library/components/Texts/Text';
import { Theme } from '../../../../../../util/theme/models';
import { fontStyles } from '../../../../../../styles/common';
import { useStyles } from '../../../../../../component-library/hooks';
-import { sanitizeString } from '../../../../../../util/string';
+import { escapeSpecialUnicode } from '../../../../../../util/string';
import { getSIWEDetails, SIWEMessage } from '../../../utils/signature';
import { useSignatureRequest } from '../../../hooks/signatures/useSignatureRequest';
import Address from '../../UI/info-row/info-value/address';
@@ -104,7 +104,7 @@ const Message = () => {
if (!signatureRequest?.messageParams?.data) {
return '';
}
- return sanitizeString(
+ return escapeSpecialUnicode(
hexToText(signatureRequest?.messageParams?.data as string),
);
}, [signatureRequest?.messageParams?.data]);
diff --git a/app/components/Views/confirmations/components/info/typed-sign-v3v4/info-section-origin-and-details/info-section-origin-and-details.tsx b/app/components/Views/confirmations/components/info/typed-sign-v3v4/info-section-origin-and-details/info-section-origin-and-details.tsx
index c8991c4a52e7..b04e1d4ea828 100644
--- a/app/components/Views/confirmations/components/info/typed-sign-v3v4/info-section-origin-and-details/info-section-origin-and-details.tsx
+++ b/app/components/Views/confirmations/components/info/typed-sign-v3v4/info-section-origin-and-details/info-section-origin-and-details.tsx
@@ -8,7 +8,10 @@ import { InfoRowDivider } from '../../../UI/info-row/divider';
import InfoSection from '../../../UI/info-row/info-section';
import InfoRowAddress from '../../../UI/info-row/info-value/address';
import DisplayURL from '../../../UI/info-row/info-value/display-url';
-import { isRecognizedPermit, parseTypedDataMessageFromSignatureRequest } from '../../../../utils/signature';
+import {
+ isRecognizedPermit,
+ parseAndNormalizeSignTypedDataFromSignatureRequest,
+} from '../../../../utils/signature';
import { useSignatureRequest } from '../../../../hooks/signatures/useSignatureRequest';
import useApprovalRequest from '../../../../hooks/useApprovalRequest';
import { View } from 'react-native';
@@ -26,9 +29,9 @@ export const InfoSectionOriginAndDetails = () => {
const signatureRequest = useSignatureRequest();
const isPermit = isRecognizedPermit(signatureRequest);
- const parsedMessage = parseTypedDataMessageFromSignatureRequest(signatureRequest);
- const spender = parsedMessage?.message?.spender;
- const verifyingContract = parsedMessage?.domain?.verifyingContract;
+ const parsedData = parseAndNormalizeSignTypedDataFromSignatureRequest(signatureRequest);
+ const spender = parsedData.message?.spender;
+ const verifyingContract = parsedData.domain?.verifyingContract;
if (!signatureRequest) {
return null;
@@ -57,13 +60,10 @@ export const InfoSectionOriginAndDetails = () => {
{isValidAddress(verifyingContract) && (
-
-
-
- )}
+
+
+
+ )}
);
};
diff --git a/app/components/Views/confirmations/components/info/typed-sign-v3v4/message.tsx b/app/components/Views/confirmations/components/info/typed-sign-v3v4/message.tsx
index 3ee07024b6ad..8eb1ae61bea6 100644
--- a/app/components/Views/confirmations/components/info/typed-sign-v3v4/message.tsx
+++ b/app/components/Views/confirmations/components/info/typed-sign-v3v4/message.tsx
@@ -7,7 +7,7 @@ import { useSignatureRequest } from '../../../hooks/signatures/useSignatureReque
import Text from '../../../../../../component-library/components/Texts/Text';
import { useStyles } from '../../../../../../component-library/hooks';
import { useTypedSignSimulationEnabled } from '../../../hooks/signatures/useTypedSignSimulationEnabled';
-import { parseSanitizeTypedDataMessage } from '../../../utils/signature';
+import { parseNormalizeAndSanitizeSignTypedData } from '../../../utils/signature';
import InfoRow from '../../UI/info-row';
import { useTokenDecimalsInTypedSignRequest } from '../../../hooks/signatures/useTokenDecimalsInTypedSignRequest';
import DataTree from '../../data-tree';
@@ -51,7 +51,7 @@ const Message = () => {
sanitizedMessage,
primaryType,
} = useMemo(
- () => parseSanitizeTypedDataMessage(typedSignData),
+ () => parseNormalizeAndSanitizeSignTypedData(typedSignData),
[typedSignData],
);
diff --git a/app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/typed-sign-permit/typed-sign-permit.tsx b/app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/typed-sign-permit/typed-sign-permit.tsx
index c632b09f8985..d29cbba270af 100644
--- a/app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/typed-sign-permit/typed-sign-permit.tsx
+++ b/app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/typed-sign-permit/typed-sign-permit.tsx
@@ -8,7 +8,7 @@ import Engine from '../../../../../../../../core/Engine';
import { safeToChecksumAddress } from '../../../../../../../../util/address';
import { PrimaryType } from '../../../../../constants/signatures';
import { useSignatureRequest } from '../../../../../hooks/signatures/useSignatureRequest';
-import { isPermitDaiRevoke, parseTypedDataMessage } from '../../../../../utils/signature';
+import { isPermitDaiRevoke, parseAndNormalizeSignTypedData } from '../../../../../utils/signature';
import InfoRow from '../../../../UI/info-row';
import InfoSection from '../../../../UI/info-row/info-section';
import PermitSimulationValueDisplay from '../components/value-display';
@@ -74,7 +74,7 @@ const PermitSimulation = () => {
message,
message: { allowed, tokenId, value },
primaryType,
- } = parseTypedDataMessage(msgData as string);
+ } = parseAndNormalizeSignTypedData(msgData as string);
const tokenDetails = extractTokenDetailsByPrimaryType(message, primaryType);
diff --git a/app/components/Views/confirmations/components/title/title.tsx b/app/components/Views/confirmations/components/title/title.tsx
index 84dacc865bfe..d22f27ab7902 100644
--- a/app/components/Views/confirmations/components/title/title.tsx
+++ b/app/components/Views/confirmations/components/title/title.tsx
@@ -12,7 +12,12 @@ import useApprovalRequest from '../../hooks/useApprovalRequest';
import { useSignatureRequest } from '../../hooks/signatures/useSignatureRequest';
import { useStandaloneConfirmation } from '../../hooks/ui/useStandaloneConfirmation';
import { useTransactionMetadataRequest } from '../../hooks/transactions/useTransactionMetadataRequest';
-import { isPermitDaiRevoke, isRecognizedPermit, isSIWESignatureRequest, parseTypedDataMessageFromSignatureRequest } from '../../utils/signature';
+import {
+ isPermitDaiRevoke,
+ isRecognizedPermit,
+ isSIWESignatureRequest,
+ parseAndNormalizeSignTypedDataFromSignatureRequest,
+} from '../../utils/signature';
import { REDESIGNED_TRANSFER_TYPES } from '../../constants/confirmations';
import styleSheet from './title.styles';
@@ -40,9 +45,10 @@ const getTitleAndSubTitle = (
const isPermit = isRecognizedPermit(signatureRequest);
if (isPermit) {
- const parsedMessage = parseTypedDataMessageFromSignatureRequest(signatureRequest) ?? {};
- const { allowed, tokenId, value } = parsedMessage?.message ?? {};
- const { verifyingContract } = parsedMessage?.domain ?? {};
+ const parsedData =
+ parseAndNormalizeSignTypedDataFromSignatureRequest(signatureRequest);
+ const { allowed, tokenId, value } = parsedData.message ?? {};
+ const { verifyingContract } = parsedData.domain ?? {};
const isERC721Permit = tokenId !== undefined;
if (isERC721Permit) {
diff --git a/app/components/Views/confirmations/hooks/signatures/useSignatureMetrics.ts b/app/components/Views/confirmations/hooks/signatures/useSignatureMetrics.ts
index c7304ec4ccec..183a83143ef9 100644
--- a/app/components/Views/confirmations/hooks/signatures/useSignatureMetrics.ts
+++ b/app/components/Views/confirmations/hooks/signatures/useSignatureMetrics.ts
@@ -14,7 +14,7 @@ import { getSignatureDecodingEventProps } from '../../utils/signature-metrics';
import { useSignatureRequest } from './useSignatureRequest';
import { useSecurityAlertResponse } from '../alerts/useSecurityAlertResponse';
import { useTypedSignSimulationEnabled } from './useTypedSignSimulationEnabled';
-import { parseTypedDataMessageFromSignatureRequest } from '../../utils/signature';
+import { parseAndNormalizeSignTypedDataFromSignatureRequest } from '../../utils/signature';
import { useSelector } from 'react-redux';
import { selectConfirmationMetricsById } from '../../../../../core/redux/slices/confirmationMetrics';
import { RootState } from '../../../../../reducers';
@@ -66,7 +66,7 @@ export const useSignatureMetrics = () => {
const { chainId, decodingData, decodingLoading, messageParams, type, id } =
signatureRequest ?? {};
- const { primaryType } = parseTypedDataMessageFromSignatureRequest(signatureRequest) ?? {};
+ const { primaryType } = parseAndNormalizeSignTypedDataFromSignatureRequest(signatureRequest);
const confirmationMetrics = useSelector((state: RootState) =>
selectConfirmationMetricsById(state, id ?? '')
diff --git a/app/components/Views/confirmations/hooks/signatures/useTokenDecimalsInTypedSignRequest.test.ts b/app/components/Views/confirmations/hooks/signatures/useTokenDecimalsInTypedSignRequest.test.ts
index b83365527041..39e223c3e7ce 100644
--- a/app/components/Views/confirmations/hooks/signatures/useTokenDecimalsInTypedSignRequest.test.ts
+++ b/app/components/Views/confirmations/hooks/signatures/useTokenDecimalsInTypedSignRequest.test.ts
@@ -2,7 +2,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { typedSignV4SignatureRequest } from '../../../../../util/test/confirm-data-helpers';
import { DataTreeInput } from '../../components/data-tree/data-tree';
-import { parseSanitizeTypedDataMessage } from '../../utils/signature';
+import { parseNormalizeAndSanitizeSignTypedData } from '../../utils/signature';
// eslint-disable-next-line import/no-namespace
import * as TokenDecimalHook from '../useGetTokenStandardAndDetails';
import { useTokenDecimalsInTypedSignRequest } from './useTokenDecimalsInTypedSignRequest';
@@ -12,7 +12,7 @@ describe('useTokenDecimalsInTypedSignRequest', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const typedSignData = signatureRequest?.messageParams?.data as any;
const { domain: { verifyingContract } = {}, sanitizedMessage } =
- parseSanitizeTypedDataMessage(typedSignData);
+ parseNormalizeAndSanitizeSignTypedData(typedSignData);
it('returns correct decimal value for typed sign signature request', () => {
jest
diff --git a/app/components/Views/confirmations/hooks/signatures/useTypedSignSimulationEnabled.ts b/app/components/Views/confirmations/hooks/signatures/useTypedSignSimulationEnabled.ts
index dadb5afda6fe..3d1cf5a164c1 100644
--- a/app/components/Views/confirmations/hooks/signatures/useTypedSignSimulationEnabled.ts
+++ b/app/components/Views/confirmations/hooks/signatures/useTypedSignSimulationEnabled.ts
@@ -6,7 +6,7 @@ import {
SignatureRequestType,
} from '@metamask/signature-controller';
import { selectUseTransactionSimulations } from '../../../../../selectors/preferencesController';
-import { isRecognizedPermit, parseTypedDataMessage } from '../../utils/signature';
+import { isRecognizedPermit, parseAndNormalizeSignTypedData } from '../../utils/signature';
import { useSignatureRequest } from './useSignatureRequest';
const NON_PERMIT_SUPPORTED_TYPES_SIGNS = [
@@ -32,7 +32,7 @@ const isNonPermitSupportedByDecodingAPI = (
const {
domain: { name, version },
primaryType,
- } = parseTypedDataMessage(data);
+ } = parseAndNormalizeSignTypedData(data);
return NON_PERMIT_SUPPORTED_TYPES_SIGNS.some(
({ domainName, primaryTypeList, versionList }) =>
diff --git a/app/components/Views/confirmations/legacy/components/PersonalSign/PersonalSign.tsx b/app/components/Views/confirmations/legacy/components/PersonalSign/PersonalSign.tsx
index eaad2b9276b3..755a265b93e6 100644
--- a/app/components/Views/confirmations/legacy/components/PersonalSign/PersonalSign.tsx
+++ b/app/components/Views/confirmations/legacy/components/PersonalSign/PersonalSign.tsx
@@ -12,7 +12,7 @@ import {
isExternalHardwareAccount,
stripHexPrefix,
} from '../../../../../../util/address';
-import { sanitizeString } from '../../../../../../util/string';
+import { escapeSpecialUnicode } from '../../../../../../util/string';
import { useTheme } from '../../../../../../util/theme';
import { WALLET_CONNECT_ORIGIN } from '../../../../../../util/walletconnect';
import SignatureRequest from '../SignatureRequest';
@@ -210,7 +210,7 @@ const PersonalSign = ({
};
const renderMessageText = () => {
- const textChild = sanitizeString(msgHexToText(messageParams.data))
+ const textChild = escapeSpecialUnicode(msgHexToText(messageParams.data))
.split('\n')
.map((line: string, i: number) => (
- {sanitizeString(key)}:
+ {escapeSpecialUnicode(key)}:
{this.renderTypedMessageV3(obj[key])}
) : (
- {sanitizeString(key)}:{' '}
- {sanitizeString(`${obj[key]}`)}
+ {escapeSpecialUnicode(key)}:{' '}
+ {escapeSpecialUnicode(`${obj[key]}`)}
)}
@@ -225,10 +223,10 @@ class TypedSign extends PureComponent {
{messageParams.data.map((obj, i) => (
- {sanitizeString(obj.name)}:
+ {escapeSpecialUnicode(obj.name)}:
- {sanitizeString(` ${obj.value}`)}
+ {escapeSpecialUnicode(` ${obj.value}`)}
))}
@@ -236,8 +234,8 @@ class TypedSign extends PureComponent {
);
}
if (messageParams.version === 'V3' || messageParams.version === 'V4') {
- const message = parseTypedSignDataMessage(messageParams.data);
- return this.renderTypedMessageV3(message);
+ const { sanitizedMessage } = parseAndSanitizeSignTypedData(messageParams.data);
+ return this.renderTypedMessageV3(sanitizedMessage);
}
};
diff --git a/app/components/Views/confirmations/utils/signature.test.ts b/app/components/Views/confirmations/utils/signature.test.ts
index 6c3523dc232c..00fc229ce75f 100644
--- a/app/components/Views/confirmations/utils/signature.test.ts
+++ b/app/components/Views/confirmations/utils/signature.test.ts
@@ -1,10 +1,11 @@
import {
- parseTypedDataMessage,
+ parseAndNormalizeSignTypedData,
isRecognizedPermit,
isTypedSignV3V4Request,
- parseTypedDataMessageFromSignatureRequest,
isRecognizedOrder,
- parseSanitizeTypedDataMessage,
+ sanitizeParsedMessage,
+ parseAndSanitizeSignTypedData,
+ parseAndNormalizeSignTypedDataFromSignatureRequest,
} from './signature';
import {
PRIMARY_TYPES_ORDER,
@@ -50,14 +51,14 @@ const mockExpectedSanitizedTypedSignV3Message = {
};
describe('Signature Utils', () => {
- describe('parseTypedDataMessage', () => {
+ describe('parseAndNormalizeSignTypedData', () => {
it('parses a typed data message correctly', () => {
const data = JSON.stringify({
message: {
value: '123',
},
});
- const result = parseTypedDataMessage(data);
+ const result = parseAndNormalizeSignTypedData(data);
expect(result).toEqual({
message: {
value: '123',
@@ -66,7 +67,7 @@ describe('Signature Utils', () => {
});
it('parses message.value as a string', () => {
- const result = parseTypedDataMessage(
+ const result = parseAndNormalizeSignTypedData(
'{"test": "dummy", "message": { "value": 3000123} }',
);
expect(result.message.value).toBe('3000123');
@@ -79,13 +80,13 @@ describe('Signature Utils', () => {
value: largeValue,
},
});
- const result = parseTypedDataMessage(data);
+ const result = parseAndNormalizeSignTypedData(data);
expect(result.message.value).toBe(largeValue);
});
it('throws an error for invalid typedDataMessage', () => {
expect(() => {
- parseTypedDataMessage('');
+ parseAndNormalizeSignTypedData('');
}).toThrow(new Error('Unexpected end of JSON input'));
});
});
@@ -173,31 +174,35 @@ describe('Signature Utils', () => {
});
});
- describe('parseTypedDataMessageFromSignatureRequest', () => {
+ describe('parseAndNormalizeSignTypedDataFromSignatureRequest', () => {
it('parses the correct primary type', () => {
expect(
- parseTypedDataMessageFromSignatureRequest(typedSignV3SignatureRequest)?.primaryType,
+ parseAndNormalizeSignTypedDataFromSignatureRequest(typedSignV3SignatureRequest)?.primaryType,
).toBe('Mail');
expect(
- parseTypedDataMessageFromSignatureRequest(typedSignV4SignatureRequest)?.primaryType,
+ parseAndNormalizeSignTypedDataFromSignatureRequest(typedSignV4SignatureRequest)?.primaryType,
).toBe('Permit');
});
- it('parses undefined for typed sign V1 message', () => {
+ it('parses {} for typed sign V1 message', () => {
expect(
- parseTypedDataMessageFromSignatureRequest(typedSignV1SignatureRequest),
- ).toBe(undefined);
+ parseAndNormalizeSignTypedDataFromSignatureRequest(typedSignV1SignatureRequest),
+ ).toStrictEqual({});
});
- it('parses undefined for personal sign message', () => {
+ it('parses {} for personal sign message', () => {
expect(
- parseTypedDataMessageFromSignatureRequest(personalSignSignatureRequest),
- ).toBe(undefined);
+ parseAndNormalizeSignTypedDataFromSignatureRequest(personalSignSignatureRequest),
+ ).toStrictEqual({});
});
});
- describe('parseSanitizeTypedDataMessage', () => {
+ describe('parseAndSanitizeSignTypedData', () => {
+ const typedDataMsg =
+ '{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF","0x06195827297c7A80a443b6894d3BDB8824b43896"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}';
+
it('returns parsed and sanitized types signature message', () => {
- const { sanitizedMessage, primaryType, domain } =
- parseSanitizeTypedDataMessage(JSON.stringify(mockTypedSignV3Message));
+ const parsedMessage =
+ parseAndSanitizeSignTypedData(JSON.stringify(mockTypedSignV3Message));
+ const { primaryType, domain, sanitizedMessage } = parsedMessage;
expect(primaryType).toBe('Mail');
expect(sanitizedMessage).toEqual(mockExpectedSanitizedTypedSignV3Message);
@@ -205,8 +210,132 @@ describe('Signature Utils', () => {
});
it('returns an empty object if no data is passed', () => {
- const result = parseSanitizeTypedDataMessage('');
+ const result = parseAndSanitizeSignTypedData('');
expect(result).toMatchObject({});
});
+
+ it('should throw an error if types is undefined', () => {
+ const typedDataMsgWithoutTypes =
+ '{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF","0x06195827297c7A80a443b6894d3BDB8824b43896"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail"}';
+ expect(() => parseAndSanitizeSignTypedData(typedDataMsgWithoutTypes)).toThrow(
+ 'Invalid types definition',
+ );
+ });
+
+ it('should throw an error if base type is not defined', () => {
+ const typedSignDataWithoutBaseType =
+ '{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF","0x06195827297c7A80a443b6894d3BDB8824b43896"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}';
+ expect(() =>
+ parseAndSanitizeSignTypedData(typedSignDataWithoutBaseType),
+ ).toThrow('Invalid primary type definition');
+ });
+
+ it('should return message data ignoring unknown types and trim new lines', () => {
+ const result = parseAndSanitizeSignTypedData(typedDataMsg);
+ expect(result.sanitizedMessage).toStrictEqual({
+ value: {
+ contents: { value: 'Hello, Bob!', type: 'string' },
+ from: {
+ value: {
+ name: { value: 'Cow', type: 'string' },
+ wallets: {
+ value: [
+ {
+ value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
+ type: 'address',
+ },
+ {
+ value: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
+ type: 'address',
+ },
+ {
+ value: '0x06195827297c7A80a443b6894d3BDB8824b43896',
+ type: 'address',
+ },
+ ],
+ type: 'address[]',
+ },
+ },
+ type: 'Person',
+ },
+ to: {
+ value: [
+ {
+ value: {
+ name: { value: 'Bob', type: 'string' },
+ wallets: {
+ value: [
+ {
+ value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
+ type: 'address',
+ },
+ {
+ value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
+ type: 'address',
+ },
+ {
+ value: '0xB0B0b0b0b0b0B000000000000000000000000000',
+ type: 'address',
+ },
+ ],
+ type: 'address[]',
+ },
+ },
+ type: 'Person',
+ },
+ ],
+ type: 'Person[]',
+ },
+ },
+ type: 'Mail',
+ });
+ });
+ });
+
+ describe('sanitizeParsedMessage', () => {
+ it('throws an error if types is undefined', () => {
+ const { message, primaryType } = mockTypedSignV3Message;
+ expect(() => sanitizeParsedMessage(message, primaryType, undefined)).toThrow(
+ 'Invalid types definition',
+ );
+ });
+
+ it('throws an error if base type is not defined', () => {
+ const { message, types } = mockTypedSignV3Message;
+ expect(() => sanitizeParsedMessage(message, '', types)).toThrow(
+ 'Invalid primary type definition',
+ );
+ });
+
+ it('returns the message data without extraneous params missing matching type definitions', () => {
+ const { message, primaryType, types } = mockTypedSignV3Message;
+ const result = sanitizeParsedMessage(message, primaryType, types);
+ expect(result).toStrictEqual({
+ value: {
+ from: {
+ value: {
+ name: { value: 'Cow', type: 'string' },
+ wallet: {
+ value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
+ type: 'address',
+ },
+ },
+ type: 'Person',
+ },
+ to: {
+ value: {
+ name: { value: 'Bob', type: 'string' },
+ wallet: {
+ value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
+ type: 'address',
+ },
+ },
+ type: 'Person',
+ },
+ contents: { value: 'Hello, Bob!', type: 'string' },
+ },
+ type: 'Mail',
+ });
+ });
});
});
diff --git a/app/components/Views/confirmations/utils/signature.ts b/app/components/Views/confirmations/utils/signature.ts
index 35880f8f1e38..47f494fe3df3 100644
--- a/app/components/Views/confirmations/utils/signature.ts
+++ b/app/components/Views/confirmations/utils/signature.ts
@@ -11,59 +11,32 @@ import {
PRIMARY_TYPES_PERMIT,
PrimaryType,
} from '../constants/signatures';
-import { sanitizeMessage } from '../../../../util/string';
+import {
+ isArrayType,
+ isSolidityType,
+ stripArrayType,
+ stripMultipleNewlines,
+ stripOneLayerofNesting,
+ } from '../../../../util/string';
import { TOKEN_ADDRESS } from '../constants/tokens';
import BigNumber from 'bignumber.js';
-/**
- * The contents of this file have been taken verbatim from
- * metamask-extension/shared/modules/transaction.utils.ts
- *
- * If updating, please be mindful of this or delete this comment.
- */
-
-const REGEX_MESSAGE_VALUE_LARGE =
- /"message"\s*:\s*\{[^}]*"value"\s*:\s*(\d{15,})/u;
+type FieldValue = string | string[] | Record;
-function extractLargeMessageValue(dataToParse: string): string | undefined {
- if (typeof dataToParse !== 'string') {
- return undefined;
- }
- return dataToParse.match(REGEX_MESSAGE_VALUE_LARGE)?.[1];
+interface BaseType {
+ name: string;
+ type: string;
}
-
-/**
- * JSON.parse has a limitation which coerces values to scientific notation if numbers are greater than
- * Number.MAX_SAFE_INTEGER. This can cause a loss in precision.
- *
- * Aside from precision concerns, if the value returned was a large number greater than 15 digits,
- * e.g. 3.000123123123121e+26, passing the value to BigNumber will throw the error:
- * Error: new BigNumber() number type has more than 15 significant digits
- *
- * Note that using JSON.parse reviver cannot help since the value will be coerced by the time it
- * reaches the reviver function.
- *
- * This function has a workaround to extract the large value from the message and replace
- * the message value with the string value.
- *
- * @param dataToParse
- * @returns
- */
-export const parseTypedDataMessage = (dataToParse: string) => {
- const result = JSON.parse(dataToParse);
-
- const messageValue = extractLargeMessageValue(dataToParse);
- if (result.message?.value) {
- result.message.value = messageValue || String(result.message.value);
- }
- return result;
-};
-
interface TypedSignatureRequest {
messageParams: MessageParamsTyped;
type: SignatureRequestType.TypedSign;
}
+interface ValueType {
+ value: FieldValue | ValueType[];
+ type: string;
+}
+
/**
* Support backwards compatibility DAI while it's still being deprecated. See EIP-2612 for more info.
*/
@@ -108,23 +81,138 @@ export const isTypedSignV3V4Request = (signatureRequest?: SignatureRequest) => {
);
};
-export const parseTypedDataMessageFromSignatureRequest = (
+/**
+ * This is a recursive method accepts a parsed, signTypedData message. It removes message params
+ * that do not have associated, valid solidity type definitions. It also strips multiple
+ * new lines in strings.
+ */
+export const sanitizeParsedMessage = (
+ message: FieldValue,
+ primaryType: string,
+ types: Record | undefined,
+): ValueType => {
+ if (!types) {
+ throw new Error(`Invalid types definition`);
+ }
+
+ // Primary type can be an array.
+ const isArray = primaryType && isArrayType(primaryType);
+ if (isArray) {
+ return {
+ value: (message as string[]).map(
+ (value: string): ValueType =>
+ sanitizeParsedMessage(value, stripOneLayerofNesting(primaryType), types),
+ ),
+ type: primaryType,
+ };
+ } else if (isSolidityType(primaryType)) {
+ return {
+ value: stripMultipleNewlines(message) as ValueType['value'],
+ type: primaryType,
+ };
+ }
+
+ // If not, assume to be struct
+ const baseType = isArray ? stripArrayType(primaryType) : primaryType;
+
+ const baseTypeDefinitions = types[baseType];
+ if (!baseTypeDefinitions) {
+ throw new Error(`Invalid primary type definition`);
+ }
+
+ const sanitizedStruct = {};
+ const msgKeys = Object.keys(message);
+ msgKeys.forEach((msgKey: string) => {
+ const definedType: BaseType | undefined = Object.values(
+ baseTypeDefinitions,
+ ).find(
+ (baseTypeDefinition: BaseType) => baseTypeDefinition.name === msgKey,
+ );
+
+ if (!definedType) {
+ return;
+ }
+
+ (sanitizedStruct as Record)[msgKey] = sanitizeParsedMessage(
+ (message as Record)[msgKey],
+ definedType.type,
+ types,
+ );
+ });
+ return { value: sanitizedStruct, type: primaryType };
+};
+
+
+const REGEX_MESSAGE_VALUE_LARGE =
+ /"message"\s*:\s*\{[^}]*"value"\s*:\s*(\d{15,})/u;
+
+/** Returns the value of the message if it is a digit greater than 15 digits */
+function extractLargeMessageValue(messageParamsData: string): string | undefined {
+ if (typeof messageParamsData !== 'string') {
+ return undefined;
+ }
+ return messageParamsData.match(REGEX_MESSAGE_VALUE_LARGE)?.[1];
+}
+
+/**
+ * JSON.parse has a limitation which coerces values to scientific notation if numbers are greater than
+ * Number.MAX_SAFE_INTEGER. This can cause a loss in precision.
+ *
+ * Aside from precision concerns, if the value returned was a large number greater than 15 digits,
+ * e.g. 3.000123123123121e+26, passing the value to BigNumber will throw the error:
+ * Error: new BigNumber() number type has more than 15 significant digits
+ *
+ * Note that using JSON.parse reviver cannot help since the value will be coerced by the time it
+ * reaches the reviver function.
+ *
+ * This function has a workaround to extract the large value from the message and replace
+ * the message value with the string value.
+ */
+export const parseAndNormalizeSignTypedData = (messageParamsData: string) => {
+ const result = JSON.parse(messageParamsData);
+
+ const largeMessageValue = extractLargeMessageValue(messageParamsData);
+ if (result.message?.value) {
+ result.message.value = largeMessageValue || String(result.message.value);
+ }
+
+ return result;
+};
+
+export const parseAndSanitizeSignTypedData = (messageParamsData: string) => {
+ if (!messageParamsData) { return {}; }
+
+ const { domain, message, primaryType, types } = JSON.parse(messageParamsData);
+ const sanitizedMessage = sanitizeParsedMessage(message, primaryType, types);
+
+ return { sanitizedMessage, primaryType, domain };
+};
+
+export const parseNormalizeAndSanitizeSignTypedData = (messageParamsData: string) => {
+ if (!messageParamsData) { return {}; }
+
+ const { domain, message, primaryType, types } = parseAndNormalizeSignTypedData(messageParamsData);
+ const sanitizedMessage = sanitizeParsedMessage(message, primaryType, types);
+
+ return { sanitizedMessage, primaryType, domain };
+};
+
+export const parseAndNormalizeSignTypedDataFromSignatureRequest = (
signatureRequest?: SignatureRequest,
) => {
if (!signatureRequest || !isTypedSignV3V4Request(signatureRequest)) {
- return;
+ return {};
}
const data = signatureRequest.messageParams?.data as string;
- return parseTypedDataMessage(data);
+ return parseAndNormalizeSignTypedData(data);
};
const isRecognizedOfType = (
request: SignatureRequest | undefined,
types: PrimaryType[],
) => {
- const { primaryType } =
- parseTypedDataMessageFromSignatureRequest(request) || {};
+ const { primaryType } = parseAndNormalizeSignTypedDataFromSignatureRequest(request);
return types.includes(primaryType);
};
@@ -144,18 +232,6 @@ export const isRecognizedPermit = (request?: SignatureRequest) =>
export const isRecognizedOrder = (request?: SignatureRequest) =>
isRecognizedOfType(request, PRIMARY_TYPES_ORDER);
-export const parseSanitizeTypedDataMessage = (dataToParse: string) => {
- if (!dataToParse) {
- return {};
- }
-
- const { domain, message, primaryType, types } =
- parseTypedDataMessage(dataToParse);
-
- const sanitizedMessage = sanitizeMessage(message, primaryType, types);
- return { sanitizedMessage, primaryType, domain };
-};
-
export interface SIWEMessage {
address: string;
chainId: string;
diff --git a/app/util/string/index.test.ts b/app/util/string/index.test.ts
index f5d7c36acea5..88dae254a0d9 100644
--- a/app/util/string/index.test.ts
+++ b/app/util/string/index.test.ts
@@ -1,159 +1,105 @@
import {
- parseTypedSignDataMessage,
- sanitizeMessage,
- sanitizeString,
+ escapeSpecialUnicode,
+ isArrayType,
+ isSolidityType,
+ stripArrayType,
stripMultipleNewlines,
+ stripOneLayerofNesting,
} from '.';
-import { mockTypedSignV3Message } from '../test/confirm-data-helpers';
describe('string utils', () => {
- describe('sanitizeString', () => {
+ describe('escapeSpecialUnicode', () => {
it('escapes all occurences of \u202E', () => {
- const result = sanitizeString('test \u202E test \u202E test');
+ const result = escapeSpecialUnicode('test \u202E test \u202E test');
expect(result).toEqual('test \\u202E test \\u202E test');
});
it('escapes all occurences of \u202D and \u202E', () => {
- const result = sanitizeString('test \u202D test \u202E test \u202D test');
+ const result = escapeSpecialUnicode('test \u202D test \u202E test \u202D test');
expect(result).toEqual('test \\u202D test \\u202E test \\u202D test');
});
});
- describe('stripMultipleNewlines', () => {
- it('replace multiple newline characters in string with single newline character', async () => {
- const result = stripMultipleNewlines(
- 'Secure ✅ \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
- );
- expect(result).toEqual('Secure ✅ \n');
+ describe('isArrayType', () => {
+ [
+ ['uint256[]', true],
+ ['address[5]', true],
+ ['string[][]', true],
+ ['bytes32[1][2]', true],
+ ['uint256', false],
+ ['address', false],
+ ['string', false],
+ ['bytes32', false],
+ ].forEach(([input, expected]) => {
+ it(`returns ${expected} for ${input}`, () => {
+ const result = isArrayType(input as string);
+ expect(result).toEqual(expected);
+ });
});
});
- describe('sanitizeMessage', () => {
- it('should throw an error if types is undefined', () => {
- const { message, primaryType } = mockTypedSignV3Message;
- expect(() => sanitizeMessage(message, primaryType, undefined)).toThrow(
- 'Invalid types definition',
- );
+ describe('isSolidityType', () => {
+ [
+ ['uint256[]', false],
+ ['address[5]', false],
+ ['string[][]', false],
+ ['bytes32[1][2]', false],
+ ['uint256', true],
+ ['address', true],
+ ['string', true],
+ ['bytes32', true],
+ ].forEach(([input, expected]) => {
+ it(`returns ${expected} for ${input}`, () => {
+ const result = isSolidityType(input as string);
+ expect(result).toEqual(expected);
+ });
});
+ });
- it('should throw an error if base type is not defined', () => {
- const { message, types } = mockTypedSignV3Message;
- expect(() => sanitizeMessage(message, '', types)).toThrow(
- 'Invalid primary type definition',
- );
+ describe('stripArrayType', () => {
+ [
+ ['uint256[]', 'uint256'],
+ ['address[5]', 'address'],
+ ['string[][]', 'string'],
+ ['bytes32[1][2]', 'bytes32'],
+ ].forEach(([input, expected]) => {
+ it(`removes the array type from ${input}`, () => {
+ const result = stripArrayType(input);
+ expect(result).toEqual(expected);
+ });
});
+ });
- it('should return message data as expected', () => {
- const { message, primaryType, types } = mockTypedSignV3Message;
- const result = sanitizeMessage(message, primaryType, types);
- expect(result).toStrictEqual({
- value: {
- from: {
- value: {
- name: { value: 'Cow', type: 'string' },
- wallet: {
- value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
- type: 'address',
- },
- },
- type: 'Person',
- },
- to: {
- value: {
- name: { value: 'Bob', type: 'string' },
- wallet: {
- value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
- type: 'address',
- },
- },
- type: 'Person',
- },
- contents: { value: 'Hello, Bob!', type: 'string' },
- },
- type: 'Mail',
+ describe('stripOneLayerofNesting', () => {
+ [
+ ['uint256[1]', 'uint256'],
+ ['address[5]', 'address'],
+ ['string[1][2]', 'string[2]'],
+ ['bytes32[1][2]', 'bytes32[2]'],
+ ].forEach(([input, expected]) => {
+ it(`removes one layer of array nesting from ${input}`, () => {
+ const result = stripOneLayerofNesting(input);
+ expect(result).toEqual(expected);
});
});
});
- describe('parseTypedSignDataMessage', () => {
- const typedDataMsg =
- '{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF","0x06195827297c7A80a443b6894d3BDB8824b43896"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}';
-
- it('should throw an error if types is undefined', () => {
- const typedDataMsgWithoutTypes =
- '{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF","0x06195827297c7A80a443b6894d3BDB8824b43896"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail"}';
- expect(() => parseTypedSignDataMessage(typedDataMsgWithoutTypes)).toThrow(
- 'Invalid types definition',
+ describe('stripMultipleNewlines', () => {
+ it('replace multiple newline characters in string with single newline character', async () => {
+ const result = stripMultipleNewlines(
+ 'Secure ✅ \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
);
+ expect(result).toEqual('Secure ✅ \n');
});
- it('should throw an error if base type is not defined', () => {
- const typedSignDataWithoutBaseType =
- '{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF","0x06195827297c7A80a443b6894d3BDB8824b43896"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}';
- expect(() =>
- parseTypedSignDataMessage(typedSignDataWithoutBaseType),
- ).toThrow('Invalid primary type definition');
+ it('returns undefined if the input is undefined', async () => {
+ const result = stripMultipleNewlines(undefined);
+ expect(result).toEqual(undefined);
});
- it('should return message data ignoring unknown types and trim new lines', () => {
- const result = parseTypedSignDataMessage(typedDataMsg);
- expect(result).toStrictEqual({
- value: {
- contents: { value: 'Hello, Bob!', type: 'string' },
- from: {
- value: {
- name: { value: 'Cow', type: 'string' },
- wallets: {
- value: [
- {
- value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
- type: 'address',
- },
- {
- value: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
- type: 'address',
- },
- {
- value: '0x06195827297c7A80a443b6894d3BDB8824b43896',
- type: 'address',
- },
- ],
- type: 'address[]',
- },
- },
- type: 'Person',
- },
- to: {
- value: [
- {
- value: {
- name: { value: 'Bob', type: 'string' },
- wallets: {
- value: [
- {
- value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
- type: 'address',
- },
- {
- value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
- type: 'address',
- },
- {
- value: '0xB0B0b0b0b0b0B000000000000000000000000000',
- type: 'address',
- },
- ],
- type: 'address[]',
- },
- },
- type: 'Person',
- },
- ],
- type: 'Person[]',
- },
- },
- type: 'Mail',
- });
+ it('returns the value as is if it is not a string', async () => {
+ const result = stripMultipleNewlines(123);
+ expect(result).toEqual(123);
});
});
});
diff --git a/app/util/string/index.ts b/app/util/string/index.ts
index bd60ae3fec21..405188afcad8 100644
--- a/app/util/string/index.ts
+++ b/app/util/string/index.ts
@@ -1,12 +1,12 @@
import { isString } from '../lodash';
/**
- * The method escapes LTR and RTL override unicode in the string
+ * The method escapes left-to-right (LTR) and right-to-left (RTL) unicode characters in the string
*
* @param {string} str
* @returns {(string|*)} escaped string or original param value
*/
-export const sanitizeString = (str: string): string => {
+export const escapeSpecialUnicode = (str: string): string => {
if (!str) {
return str;
}
@@ -18,7 +18,7 @@ export const sanitizeString = (str: string): string => {
return str.split('\u202D').join('\\u202D').split('\u202E').join('\\u202E');
};
-export const stripMultipleNewlines = (str: string): string => {
+export const stripMultipleNewlines = (str: string | unknown): string | unknown => {
if (!str || typeof str !== 'string') {
return str;
}
@@ -72,86 +72,13 @@ const solidityTypes = () => {
const SOLIDITY_TYPES = solidityTypes();
-const stripArrayType = (potentialArrayType: string) =>
+export const stripArrayType = (potentialArrayType: string) =>
potentialArrayType.replace(/\[[[0-9]*\]*/gu, '');
-const stripOneLayerofNesting = (potentialArrayType: string) =>
+export const stripOneLayerofNesting = (potentialArrayType: string) =>
potentialArrayType.replace(/\[(\d*)\]/u, '');
-const isArrayType = (potentialArrayType: string) =>
+export const isArrayType = (potentialArrayType: string) =>
potentialArrayType.match(/\[[[0-9]*\]*/u) !== null;
-const isSolidityType = (type: string) => SOLIDITY_TYPES.includes(type);
-
-interface BaseType {
- name: string;
- type: string;
-}
-
-type FieldValue = string | string[] | Record;
-
-interface ValueType {
- value: FieldValue | ValueType[];
- type: string;
-}
-
-export const sanitizeMessage = (
- message: FieldValue,
- primaryType: string,
- types: Record | undefined,
-): ValueType => {
- if (!types) {
- throw new Error(`Invalid types definition`);
- }
-
- // Primary type can be an array.
- const isArray = primaryType && isArrayType(primaryType);
- if (isArray) {
- return {
- value: (message as string[]).map(
- (value: string): ValueType =>
- sanitizeMessage(value, stripOneLayerofNesting(primaryType), types),
- ),
- type: primaryType,
- };
- } else if (isSolidityType(primaryType)) {
- return {
- value: stripMultipleNewlines(message as string),
- type: primaryType,
- };
- }
-
- // If not, assume to be struct
- const baseType = isArray ? stripArrayType(primaryType) : primaryType;
-
- const baseTypeDefinitions = types[baseType];
- if (!baseTypeDefinitions) {
- throw new Error(`Invalid primary type definition`);
- }
-
- const sanitizedStruct = {};
- const msgKeys = Object.keys(message);
- msgKeys.forEach((msgKey: string) => {
- const definedType: BaseType | undefined = Object.values(
- baseTypeDefinitions,
- ).find(
- (baseTypeDefinition: BaseType) => baseTypeDefinition.name === msgKey,
- );
-
- if (!definedType) {
- return;
- }
-
- (sanitizedStruct as Record)[msgKey] = sanitizeMessage(
- (message as Record)[msgKey],
- definedType.type,
- types,
- );
- });
- return { value: sanitizedStruct, type: primaryType };
-};
-
-export const parseTypedSignDataMessage = (dataToParse: string) => {
- const { message, primaryType, types } = JSON.parse(dataToParse);
- return sanitizeMessage(message, primaryType, types);
-};
+export const isSolidityType = (type: string) => SOLIDITY_TYPES.includes(type);