1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Fix a bug where non-address types would be rendered as addresses in EIP-712 (#17846)

* Fix EIP-712 rendering logic

* Fix tests

* Fix tests and story

* Fix lint

* Fix import

* Fix stories
This commit is contained in:
Frederik Bolding 2023-02-27 17:32:51 +01:00 committed by GitHub
parent 932282e638
commit 64bfe6f307
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 543 additions and 337 deletions

View File

@ -26,7 +26,7 @@ function SignatureRequestData({ data }) {
return ( return (
<Box className="signature-request-data__node"> <Box className="signature-request-data__node">
{Object.entries(data).map(([label, value], i) => ( {Object.entries(data).map(([label, { value, type }], i) => (
<Box <Box
className="signature-request-data__node" className="signature-request-data__node"
key={`${label}-${i}`} key={`${label}-${i}`}
@ -54,7 +54,8 @@ function SignatureRequestData({ data }) {
marginLeft={4} marginLeft={4}
className="signature-request-data__node__value" className="signature-request-data__node__value"
> >
{isValidHexAddress(value, { {type === 'address' &&
isValidHexAddress(value, {
mixedCaseUseChecksum: true, mixedCaseUseChecksum: true,
}) ? ( }) ? (
<Typography <Typography

View File

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { sanitizeMessage } from '../../../../helpers/utils/util';
import SignatureRequestData from './signature-request-data'; import SignatureRequestData from './signature-request-data';
export default { export default {
@ -16,38 +17,58 @@ export const DefaultStory = (args) => {
DefaultStory.storyName = 'Default'; DefaultStory.storyName = 'Default';
DefaultStory.args = { const rawMessage = {
data: JSON.parse( domain: {
JSON.stringify({ chainId: 97,
domain: { name: 'Ether Mail',
name: 'happydapp.website', verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
}, version: '1',
message: { },
string: 'haay wuurl', message: {
number: 42, contents: 'Hello, Bob!',
}, from: {
primaryType: 'Mail', name: 'Cow',
types: { wallets: [
EIP712Domain: [ '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
{ name: 'name', type: 'string' }, '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
{ name: 'version', type: 'string' }, '0x06195827297c7A80a443b6894d3BDB8824b43896',
{ name: 'chainId', type: 'uint256' }, ],
{ name: 'verifyingContract', type: 'address' }, },
], to: [
Group: [ {
{ name: 'name', type: 'string' }, name: 'Bob',
{ name: 'members', type: 'Person[]' }, wallets: [
], '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
Mail: [ '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
{ name: 'from', type: 'Person' }, '0xB0B0b0b0b0b0B000000000000000000000000000',
{ name: 'to', type: 'Person[]' },
{ name: 'contents', type: 'string' },
],
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallets', type: 'address[]' },
], ],
}, },
}), ],
), },
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[]' },
],
},
};
DefaultStory.args = {
data: sanitizeMessage(
rawMessage.message,
rawMessage.primaryType,
rawMessage.types,
).value,
}; };

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import configureMockStore from 'redux-mock-store'; import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import { sanitizeMessage } from '../../../../helpers/utils/util';
import Identicon from '../../../ui/identicon'; import Identicon from '../../../ui/identicon';
import SignatureRequestData from './signature-request-data'; import SignatureRequestData from './signature-request-data';
@ -59,124 +60,65 @@ describe('Signature Request Data', () => {
}, },
}; };
let messageData;
const store = configureMockStore()(mockStore); const store = configureMockStore()(mockStore);
beforeEach(() => { const rawMessage = {
messageData = { domain: {
domain: { chainId: 97,
chainId: 97, name: 'Ether Mail',
name: 'Ether Mail', verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', version: '1',
version: '1', },
message: {
contents: 'Hello, Bob!',
from: {
name: 'Cow',
wallets: [
'0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
'0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
'0x06195827297c7A80a443b6894d3BDB8824b43896',
],
}, },
message: { to: [
contents: 'Hello, Bob!', {
from: { name: 'Bob',
name: 'Cow',
wallets: [ wallets: [
'0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
'0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
'0x06195827297c7A80a443b6894d3BDB8824b43896', '0xB0B0b0b0b0b0B000000000000000000000000000',
], ],
}, },
to: [ ],
{ },
name: 'Bob', primaryType: 'Mail',
wallets: [ types: {
'0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', EIP712Domain: [
'0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', { name: 'name', type: 'string' },
'0xB0B0b0b0b0b0B000000000000000000000000000', { name: 'version', type: 'string' },
], { name: 'chainId', type: 'uint256' },
}, { name: 'verifyingContract', type: 'address' },
], ],
}, Mail: [
primaryType: 'Mail', { name: 'from', type: 'Person' },
types: { { name: 'to', type: 'Person[]' },
EIP712Domain: [ { name: 'contents', type: 'string' },
{ name: 'name', type: 'string' }, ],
{ name: 'version', type: 'string' }, Person: [
{ name: 'chainId', type: 'uint256' }, { name: 'name', type: 'string' },
{ name: 'verifyingContract', type: 'address' }, { name: 'wallets', 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 render domain chainId', () => { const messageData = sanitizeMessage(
const msgParams = { rawMessage.message,
data: JSON.parse(JSON.stringify(messageData)), rawMessage.primaryType,
version: 'V4', rawMessage.types,
origin: 'test', );
};
const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />,
store,
);
expect(getByText('97')).toBeInTheDocument();
});
it('should render domain name', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />,
store,
);
expect(getByText('Ether Mail')).toBeInTheDocument();
});
it('should render Identicon for domain verifying contract', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = (
<Identicon
diameter={32}
address={msgParams.data.domain.verifyingContract}
/>
);
expect(iconImage).toBeDefined();
});
it('should render domain verifying contract shorten address', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />,
store,
);
expect(getByText('0xCcC...cccC')).toBeInTheDocument();
});
it('should render contents title', () => { it('should render contents title', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -184,13 +126,8 @@ describe('Signature Request Data', () => {
}); });
it('should render contants text', () => { it('should render contants text', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -198,13 +135,8 @@ describe('Signature Request Data', () => {
}); });
it('should render from title', () => { it('should render from title', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -212,13 +144,8 @@ describe('Signature Request Data', () => {
}); });
it('should render name title in "from" object', () => { it('should render name title in "from" object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams.data.message.from} />, <SignatureRequestData data={messageData.value.from.value} />,
store, store,
); );
@ -226,13 +153,8 @@ describe('Signature Request Data', () => {
}); });
it('should render name text in "from" object', () => { it('should render name text in "from" object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -240,13 +162,8 @@ describe('Signature Request Data', () => {
}); });
it('should render wallets title in "from" object', () => { it('should render wallets title in "from" object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams.data.message.from} />, <SignatureRequestData data={messageData.value.from.value} />,
store, store,
); );
@ -254,28 +171,18 @@ describe('Signature Request Data', () => {
}); });
it('should render Identicon for first wallet in "from" object', () => { it('should render Identicon for first wallet in "from" object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = ( const iconImage = (
<Identicon <Identicon
diameter={32} diameter={32}
address={msgParams.data.message.from.wallets[0]} address={messageData.value.from.value.wallets.value[0].value}
/> />
); );
expect(iconImage).toBeDefined(); expect(iconImage).toBeDefined();
}); });
it('should render first account name from wallets array if address exists in identities object', () => { it('should render first account name from wallets array if address exists in identities object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -283,28 +190,18 @@ describe('Signature Request Data', () => {
}); });
it('should render Identicon for second wallet in "from" object', () => { it('should render Identicon for second wallet in "from" object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = ( const iconImage = (
<Identicon <Identicon
diameter={32} diameter={32}
address={msgParams.data.message.from.wallets[1]} address={messageData.value.from.value.wallets.value[1].value}
/> />
); );
expect(iconImage).toBeDefined(); expect(iconImage).toBeDefined();
}); });
it('should render second account name from wallets array if address exists in identities object', () => { it('should render second account name from wallets array if address exists in identities object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -312,28 +209,18 @@ describe('Signature Request Data', () => {
}); });
it('should render Identicon for third wallet in "from" object', () => { it('should render Identicon for third wallet in "from" object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = ( const iconImage = (
<Identicon <Identicon
diameter={32} diameter={32}
address={msgParams.data.message.from.wallets[2]} address={messageData.value.from.value.wallets.value[2].value}
/> />
); );
expect(iconImage).toBeDefined(); expect(iconImage).toBeDefined();
}); });
it('should render third account name from wallets array if address exists in address book object', () => { it('should render third account name from wallets array if address exists in address book object', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -341,13 +228,8 @@ describe('Signature Request Data', () => {
}); });
it('should render name title in "to" array of objects', () => { it('should render name title in "to" array of objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams.data.message.to[0]} />, <SignatureRequestData data={messageData.value.to.value[0].value} />,
store, store,
); );
@ -355,13 +237,8 @@ describe('Signature Request Data', () => {
}); });
it('should render name text in "to" array of objects', () => { it('should render name text in "to" array of objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams.data.message.to[0]} />, <SignatureRequestData data={messageData.value.to.value[0].value} />,
store, store,
); );
@ -369,13 +246,8 @@ describe('Signature Request Data', () => {
}); });
it('should render wallets title in "to" array of objects', () => { it('should render wallets title in "to" array of objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams.data.message.to[0]} />, <SignatureRequestData data={messageData.value.to.value[0].value} />,
store, store,
); );
@ -383,28 +255,18 @@ describe('Signature Request Data', () => {
}); });
it('should render Identicon for first wallet in "to" array of objects', () => { it('should render Identicon for first wallet in "to" array of objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = ( const iconImage = (
<Identicon <Identicon
diameter={32} diameter={32}
address={msgParams.data.message.to[0].wallets[0]} address={messageData.value.to.value[0].value.wallets.value[0].value}
/> />
); );
expect(iconImage).toBeDefined(); expect(iconImage).toBeDefined();
}); });
it('should render first shorten address from wallets array if address does not exists in identities and address book objects', () => { it('should render first shorten address from wallets array if address does not exists in identities and address book objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -412,28 +274,18 @@ describe('Signature Request Data', () => {
}); });
it('should render Identicon for second wallet in "to" array of objects', () => { it('should render Identicon for second wallet in "to" array of objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = ( const iconImage = (
<Identicon <Identicon
diameter={32} diameter={32}
address={msgParams.data.message.to[0].wallets[1]} address={messageData.value.to.value[0].value.wallets.value[1].value}
/> />
); );
expect(iconImage).toBeDefined(); expect(iconImage).toBeDefined();
}); });
it('should render second shorten address from wallets array if address does not exists in identities and address book objects', () => { it('should render second shorten address from wallets array if address does not exists in identities and address book objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -441,28 +293,18 @@ describe('Signature Request Data', () => {
}); });
it('should render Identicon for third wallet in "to" array of objects', () => { it('should render Identicon for third wallet in "to" array of objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const iconImage = ( const iconImage = (
<Identicon <Identicon
diameter={32} diameter={32}
address={msgParams.data.message.to[0].wallets[2]} address={messageData.value.to.value[0].value.wallets.value[2].value}
/> />
); );
expect(iconImage).toBeDefined(); expect(iconImage).toBeDefined();
}); });
it('should render third shorten address from wallets array if address does not exists in identities and address book objects', () => { it('should render third shorten address from wallets array if address does not exists in identities and address book objects', () => {
const msgParams = {
data: JSON.parse(JSON.stringify(messageData)),
version: 'V4',
origin: 'test',
};
const { getByText } = renderWithProvider( const { getByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={messageData.value} />,
store, store,
); );
@ -471,9 +313,9 @@ describe('Signature Request Data', () => {
it('should escape RTL character in label or value', () => { it('should escape RTL character in label or value', () => {
const messageDataWithRTLCharacters = { const messageDataWithRTLCharacters = {
...messageData, ...rawMessage,
message: { message: {
...messageData.message, ...rawMessage.message,
contents: 'Hello, \u202E Bob!', contents: 'Hello, \u202E Bob!',
from: { from: {
'name\u202Ename': 'Cow \u202E Cow', 'name\u202Ename': 'Cow \u202E Cow',
@ -495,20 +337,20 @@ describe('Signature Request Data', () => {
], ],
}, },
types: { types: {
...messageData.message.types, ...rawMessage.types,
Person: [ Person: [
{ name: 'name\u202Ename', type: 'string' }, { name: 'name\u202Ename', type: 'string' },
{ name: 'wallets\u202Ewallets', type: 'address[]' }, { name: 'wallets\u202Ewallets', type: 'address[]' },
], ],
}, },
}; };
const msgParams = { const data = sanitizeMessage(
data: JSON.parse(JSON.stringify(messageDataWithRTLCharacters)), messageDataWithRTLCharacters.message,
version: 'V4', messageDataWithRTLCharacters.primaryType,
origin: 'test', messageDataWithRTLCharacters.types,
}; );
const { getByText, getAllByText } = renderWithProvider( const { getByText, getAllByText } = renderWithProvider(
<SignatureRequestData data={msgParams} />, <SignatureRequestData data={data.value} />,
store, store,
); );

View File

@ -87,7 +87,7 @@ export default function SignatureRequestMessage({
> >
{primaryType} {primaryType}
</Typography> </Typography>
<SignatureRequestData data={data} /> <SignatureRequestData data={data.value} />
</Box> </Box>
</Box> </Box>
); );

View File

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { sanitizeMessage } from '../../../../helpers/utils/util';
import SignatureRequestMessage from './signature-request-message'; import SignatureRequestMessage from './signature-request-message';
export default { export default {
@ -20,39 +21,59 @@ export const DefaultStory = (args) => {
DefaultStory.storyName = 'Default'; DefaultStory.storyName = 'Default';
const rawMessage = {
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[]' },
],
},
};
DefaultStory.args = { DefaultStory.args = {
data: JSON.parse( data: sanitizeMessage(
JSON.stringify({ rawMessage.message,
domain: { rawMessage.primaryType,
name: 'happydapp.website', rawMessage.types,
},
message: {
string: 'haay wuurl',
number: 42,
},
primaryType: 'Mail',
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
Group: [
{ name: 'name', type: 'string' },
{ name: 'members', type: 'Person[]' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person[]' },
{ name: 'contents', type: 'string' },
],
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallets', type: 'address[]' },
],
},
}),
), ),
messageIsScrollable: true, messageIsScrollable: true,
}; };

View File

@ -444,11 +444,14 @@ export const sanitizeMessage = (msg, primaryType, types) => {
// Primary type can be an array. // Primary type can be an array.
const isArray = primaryType && isArrayType(primaryType); const isArray = primaryType && isArrayType(primaryType);
if (isArray) { if (isArray) {
return msg.map((value) => return {
sanitizeMessage(value, stripOneLayerofNesting(primaryType), types), value: msg.map((value) =>
); sanitizeMessage(value, stripOneLayerofNesting(primaryType), types),
),
type: primaryType,
};
} else if (isSolidityType(primaryType)) { } else if (isSolidityType(primaryType)) {
return msg; return { value: msg, type: primaryType };
} }
// If not, assume to be struct // If not, assume to be struct
@ -459,7 +462,7 @@ export const sanitizeMessage = (msg, primaryType, types) => {
throw new Error(`Invalid primary type definition`); throw new Error(`Invalid primary type definition`);
} }
const sanitizedMessage = {}; const sanitizedStruct = {};
const msgKeys = Object.keys(msg); const msgKeys = Object.keys(msg);
msgKeys.forEach((msgKey) => { msgKeys.forEach((msgKey) => {
const definedType = Object.values(baseTypeDefinitions).find( const definedType = Object.values(baseTypeDefinitions).find(
@ -470,13 +473,13 @@ export const sanitizeMessage = (msg, primaryType, types) => {
return; return;
} }
sanitizedMessage[msgKey] = sanitizeMessage( sanitizedStruct[msgKey] = sanitizeMessage(
msg[msgKey], msg[msgKey],
definedType.type, definedType.type,
types, types,
); );
}); });
return sanitizedMessage; return { value: sanitizedStruct, type: primaryType };
}; };
export function getAssetImageURL(image, ipfsGateway) { export function getAssetImageURL(image, ipfsGateway) {

View File

@ -478,12 +478,107 @@ describe('util', () => {
it('should return parsed message if types is defined', () => { it('should return parsed message if types is defined', () => {
const result = util.sanitizeMessage(message, primaryType, types); const result = util.sanitizeMessage(message, primaryType, types);
expect(result.contents).toStrictEqual('Hello, Bob!'); expect(result).toStrictEqual({
expect(result.from.name).toStrictEqual('Cow'); type: 'Mail',
expect(result.from.wallets).toHaveLength(2); value: {
expect(result.to).toHaveLength(1); contents: {
expect(result.to[0].name).toStrictEqual('Bob'); type: 'string',
expect(result.to[0].wallets).toHaveLength(3); value: 'Hello, Bob!',
},
from: {
type: 'Person',
value: {
name: {
type: 'string',
value: 'Cow',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
{
type: 'address',
value: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
},
],
},
},
},
nestArray: {
type: 'uint256[2][2]',
value: [
{
type: 'uint256[2]',
value: [
{
type: 'uint256',
value: 12,
},
{
type: 'uint256',
value: 34,
},
{
type: 'uint256',
value: 56,
},
],
},
{
type: 'uint256[2]',
value: [
{
type: 'uint256',
value: 56,
},
{
type: 'uint256',
value: 78,
},
{
type: 'uint256',
value: 89,
},
],
},
],
},
to: {
type: 'Person[]',
value: [
{
type: 'Person',
value: {
name: {
type: 'string',
value: 'Bob',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
{
type: 'address',
value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
},
{
type: 'address',
value: '0xB0B0b0b0b0b0B000000000000000000000000000',
},
],
},
},
},
],
},
},
});
}); });
it('should return parsed nested array if defined', () => { it('should return parsed nested array if defined', () => {
@ -497,10 +592,50 @@ describe('util', () => {
primaryType, primaryType,
types, types,
); );
expect(result.nestArray).toHaveLength(2); expect(result).toStrictEqual({
expect(result.nestArray[0]).toHaveLength(3); type: 'Mail',
expect(result.nestArray[0][0]).toStrictEqual(12); value: {
expect(result.nestArray[0][2]).toStrictEqual(56); nestArray: {
type: 'uint256[2][2]',
value: [
{
type: 'uint256[2]',
value: [
{
type: 'uint256',
value: 12,
},
{
type: 'uint256',
value: 34,
},
{
type: 'uint256',
value: 56,
},
],
},
{
type: 'uint256[2]',
value: [
{
type: 'uint256',
value: 56,
},
{
type: 'uint256',
value: 78,
},
{
type: 'uint256',
value: 89,
},
],
},
],
},
},
});
}); });
it('should return parsed nested array with struct if defined', () => { it('should return parsed nested array with struct if defined', () => {
@ -537,14 +672,104 @@ describe('util', () => {
], ],
}; };
const result = util.sanitizeMessage(msg, primaryType, types); const result = util.sanitizeMessage(msg, primaryType, types);
expect(result.nestedPeople).toHaveLength(2); expect(result).toStrictEqual({
expect(result.nestedPeople[0]).toHaveLength(1); type: 'Mail',
expect(result.nestedPeople[0][0].name).toStrictEqual('Bob'); value: {
expect(result.nestedPeople[0][0].wallets).toHaveLength(3); nestedPeople: {
expect(result.nestedPeople[0][0].wallets[0]).toStrictEqual( type: 'Person[][]',
'0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', value: [
); {
expect(result.nestedPeople[1][1].name).toStrictEqual('Brandon'); type: 'Person[]',
value: [
{
type: 'Person',
value: {
name: {
type: 'string',
value: 'Bob',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
{
type: 'address',
value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
},
{
type: 'address',
value: '0xB0B0b0b0b0b0B000000000000000000000000000',
},
],
},
},
},
],
},
{
type: 'Person[]',
value: [
{
type: 'Person',
value: {
name: {
type: 'string',
value: 'Ben',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
{
type: 'address',
value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
},
{
type: 'address',
value: '0xB0B0b0b0b0b0B000000000000000000000000000',
},
],
},
},
},
{
type: 'Person',
value: {
name: {
type: 'string',
value: 'Brandon',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
{
type: 'address',
value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
},
{
type: 'address',
value: '0xB0B0b0b0b0b0B000000000000000000000000000',
},
],
},
},
},
],
},
],
},
},
});
}); });
it('should return ignore message data with unknown types', () => { it('should return ignore message data with unknown types', () => {
@ -555,14 +780,107 @@ describe('util', () => {
// result will NOT contain the do_not_displays because type definition // result will NOT contain the do_not_displays because type definition
const result = util.sanitizeMessage(message, primaryType, types); const result = util.sanitizeMessage(message, primaryType, types);
expect(result.contents).toStrictEqual('Hello, Bob!'); expect(result).toStrictEqual({
expect(result.from.name).toStrictEqual('Cow'); type: 'Mail',
expect(result.from.wallets).toHaveLength(2); value: {
expect(result.to).toHaveLength(1); contents: {
expect(result.to[0].name).toStrictEqual('Bob'); type: 'string',
expect(result.to[0].wallets).toHaveLength(3); value: 'Hello, Bob!',
expect(result.do_not_display).toBeUndefined(); },
expect(result.do_not_display_2).toBeUndefined(); from: {
type: 'Person',
value: {
name: {
type: 'string',
value: 'Cow',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
{
type: 'address',
value: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
},
],
},
},
},
nestArray: {
type: 'uint256[2][2]',
value: [
{
type: 'uint256[2]',
value: [
{
type: 'uint256',
value: 12,
},
{
type: 'uint256',
value: 34,
},
{
type: 'uint256',
value: 56,
},
],
},
{
type: 'uint256[2]',
value: [
{
type: 'uint256',
value: 56,
},
{
type: 'uint256',
value: 78,
},
{
type: 'uint256',
value: 89,
},
],
},
],
},
to: {
type: 'Person[]',
value: [
{
type: 'Person',
value: {
name: {
type: 'string',
value: 'Bob',
},
wallets: {
type: 'address[]',
value: [
{
type: 'address',
value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
{
type: 'address',
value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
},
{
type: 'address',
value: '0xB0B0b0b0b0b0B000000000000000000000000000',
},
],
},
},
},
],
},
},
});
}); });
}); });
}); });