Skip to content

Commit

Permalink
fix: struct array hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
calvwang9 committed Jul 19, 2022
1 parent 8969dec commit e1f82df
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
44 changes: 44 additions & 0 deletions __mocks__/typedDataStructArrayExample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"types": {
"StarkNetDomain": [
{ "name": "name", "type": "felt" },
{ "name": "version", "type": "felt" },
{ "name": "chainId", "type": "felt" }
],
"Person": [
{ "name": "name", "type": "felt" },
{ "name": "wallet", "type": "felt" }
],
"Post": [
{ "name": "title", "type": "felt" },
{ "name": "content", "type": "felt" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person" },
{ "name": "posts_len", "type": "felt" },
{ "name": "posts", "type": "Post*" }
]
},
"primaryType": "Mail",
"domain": {
"name": "StarkNet Mail",
"version": "1",
"chainId": 1
},
"message": {
"from": {
"name": "Cow",
"wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
},
"to": {
"name": "Bob",
"wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
},
"posts_len": 2,
"posts": [
{ "title": "Greeting", "content": "Hello, Bob!" },
{ "title": "Farewell", "content": "Goodbye, Bob!" }
]
}
}
24 changes: 24 additions & 0 deletions __tests__/utils/typedData.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typedDataExample from '../../__mocks__/typedDataExample.json';
import typedDataStructArrayExample from '../../__mocks__/typedDataStructArrayExample.json';
import { number } from '../../src';
import { BigNumberish } from '../../src/utils/number';
import { encodeType, getMessageHash, getStructHash, getTypeHash } from '../../src/utils/typedData';
Expand All @@ -9,7 +10,12 @@ describe('typedData', () => {
expect(typeEncoding).toMatchInlineSnapshot(
`"Mail(from:Person,to:Person,contents:felt)Person(name:felt,wallet:felt)"`
);
const typeEncodingStructArr = encodeType(typedDataStructArrayExample, 'Mail');
expect(typeEncodingStructArr).toMatchInlineSnapshot(
`"Mail(from:Person,to:Person,posts_len:felt,posts:Post*)Person(name:felt,wallet:felt)Post(title:felt,content:felt)"`
);
});

test('should get right type hash', () => {
const typeHashDomain = getTypeHash(typedDataExample, 'StarkNetDomain');
expect(typeHashDomain).toMatchInlineSnapshot(
Expand All @@ -23,18 +29,36 @@ describe('typedData', () => {
expect(typeHashMail).toMatchInlineSnapshot(
`"0x13d89452df9512bf750f539ba3001b945576243288137ddb6c788457d4b2f79"`
);
const typeHashPost = getTypeHash(typedDataStructArrayExample, 'Post');
expect(typeHashPost).toMatchInlineSnapshot(
`"0x1d71e69bf476486b43cdcfaf5a85c00bb2d954c042b281040e513080388356d"`
);
const typeHashMailWithStructArray = getTypeHash(typedDataStructArrayExample, 'Mail');
expect(typeHashMailWithStructArray).toMatchInlineSnapshot(
`"0x873b878e35e258fc99e3085d5aaad3a81a0c821f189c08b30def2cde55ff27"`
);
});

test('should get right hash for StarkNetDomain', () => {
const hash = getStructHash(typedDataExample, 'StarkNetDomain', typedDataExample.domain as any);
expect(hash).toMatchInlineSnapshot(
`"0x54833b121883a3e3aebff48ec08a962f5742e5f7b973469c1f8f4f55d470b07"`
);
});

test('should get right hash for entire message', () => {
const hash = getMessageHash(typedDataExample, '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826');
expect(hash).toMatchInlineSnapshot(
`"0x6fcff244f63e38b9d88b9e3378d44757710d1b244282b435cb472053c8d78d0"`
);

const hashStructArr = getMessageHash(
typedDataStructArrayExample,
'0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'
);
expect(hashStructArr).toMatchInlineSnapshot(
`"0x5914ed2764eca2e6a41eb037feefd3d2e33d9af6225a9e7fe31ac943ff712c"`
);
});

interface StringStruct {
Expand Down
18 changes: 18 additions & 0 deletions src/utils/typedData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export const getDependencies = (
throw new Error('Typed data does not match JSON schema');
}

// Include pointers (struct arrays)
if (type[type.length - 1] === '*') {
// eslint-disable-next-line no-param-reassign
type = type.slice(0, -1);
}

if (dependencies.includes(type)) {
return dependencies;
}
Expand Down Expand Up @@ -102,6 +108,18 @@ const encodeValue = (typedData: TypedData, type: string, data: unknown): [string
return [type, getStructHash(typedData, type, data as Record<string, unknown>)];
}

if (
Object.keys(typedData.types)
.map((x) => `${x}*`)
.includes(type)
) {
const structHashes: string[] = (data as unknown[]).map((struct) => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return getStructHash(typedData, type.slice(0, -1), struct as Record<string, unknown>);
});
return [type, computeHashOnElements(structHashes)];
}

if (type === 'felt*') {
return ['felt*', computeHashOnElements(data as string[])];
}
Expand Down

0 comments on commit e1f82df

Please sign in to comment.