Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow TypedDataUtils to be called unbound #152

Merged
merged 1 commit into from
Aug 3, 2021

Conversation

Gudahtt
Copy link
Member

@Gudahtt Gudahtt commented Jul 14, 2021

Previously the functions exposed as TypedDataUtils could only be called from the TypedDataUtils object. If they were called unbound, they would throw errors because of the use of this.

They have all been updated to no longer rely upon this, so they now work the same way regardless how they are bound when called.

They are still exported as the TypedDataUtils object, so this should not change the API. This was done to simplify the code, specifically to make it easier for functions outside of TypedDataUtils to reuse code inside of TypedDataUtils.

Some types required adjustments, as type mistakes were brought to light that TypeScript for some reason wasn't aware of when these were declared as properties of the TypedDataUtils object. These were fixed by adding two type assertions, making the types parameter to hashStruct and hashType more strict, and by making the typedData parameter to eip712Hash more strict. The type assertions (warranted or not) preserve the types used previously. We can replace them later with validation.

@Gudahtt Gudahtt requested a review from a team as a code owner July 14, 2021 21:06
@Gudahtt Gudahtt force-pushed the allow-sign-typed-data-utilties-to-be-called-unbound branch 2 times, most recently from 9ede8b9 to 910deeb Compare July 14, 2021 21:11
function hashStruct(
primaryType: string,
data: Record<string, unknown>,
types: Record<string, MessageTypeProperty[]>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the parameter type adjustment that was required to eliminate type errors. Clearly this is required because it's passed straight to encodeData, which itself required the types parameter to be of this type.

field.type,
// TODO: Add validation to ensure this is a string-indexed
// object, so that this type cast can be removed
value as Record<string, unknown>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the first type assertion that was required. This should be guaranteed to be a Record<string, any> for any properly formatted message, but we don't have sufficient type information at this point to guarantee that. We can add that later.

sanitizedData.domain,
hashStruct(
// TODO: Validate that this is a string, so this type cast can be removed.
sanitizedData.primaryType as string,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the second type assertion that was required. At first it looked like this was already guaranteed to be a string, because primaryType is a keyof the MessageTypes object, and that's string-indexed. But apparently TypeScript is screwy when it comes to index types, and it happily allows using a number index as well (I tested it to be sure), despite this attempt at preventing that. So technically this could be a number. But that's clearly against the spec, and it's clearly what we were trying to prevent with that type.

We can shore this up later with runtime validation. Or better types. Or both.

test/index.ts Outdated
@@ -1389,3 +1389,122 @@ test('signedTypeMessage V4 with recursive types', (t) => {
'0xf2ec61e636ff7bb3ac8bc2a4cc2c8b8f635dd1b2ec8094c963128b358e79c85c5ca6dd637ed7e80f0436fe8fce39c0e5f2082c9517fe677cc2917dcd6c84ba881c',
);
});

test('unbound sign typed data utility functions', (t) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested that these all failed on the main branch.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will need to be converted to jest style to go along with this PR: #161

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@Gudahtt
Copy link
Member Author

Gudahtt commented Jul 14, 2021

I'd strongly recommend hiding whitespace when looking at this diff. It's a mess when whitespace is shown because everything was de-indented.

useV4 = true,
): Buffer {
const encodedTypes = ['bytes32'];
const encodedValues: unknown[] = [hashType(primaryType, types)];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was another type change that was required. TypeScript assumed that this was supposed to be a Buffer array because the first entry was a Buffer. But it looks like it's just an array of unknown data, not just of buffers.

*/
function hashType(
primaryType: string,
types: Record<string, MessageTypeProperty[]>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parameter type changed for the same reason as hashStruct

* @returns {Buffer} - keccak hash of the resulting signed message
*/
function eip712Hash<T extends MessageTypes>(
typedData: TypedData | TypedMessage<T>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was never actually passed in Partial<> data. Also sanitizeData requires that the typed data be complete.

@Gudahtt Gudahtt force-pushed the allow-sign-typed-data-utilties-to-be-called-unbound branch from 910deeb to 982c020 Compare July 14, 2021 21:51
@Gudahtt
Copy link
Member Author

Gudahtt commented Jul 14, 2021

Just rebased this onto main and updated the commit message. No other changes made.

@Gudahtt Gudahtt force-pushed the allow-sign-typed-data-utilties-to-be-called-unbound branch from 982c020 to 3343934 Compare July 15, 2021 16:21
@shanejonas
Copy link

Havent touched this repo yet, but the changes to typings look good, +1 for removal of this.

shanejonas
shanejonas previously approved these changes Jul 22, 2021
@Gudahtt Gudahtt force-pushed the allow-sign-typed-data-utilties-to-be-called-unbound branch 2 times, most recently from c8ee6a8 to d1b3605 Compare July 26, 2021 19:38
@Gudahtt
Copy link
Member Author

Gudahtt commented Jul 26, 2021

Thanks for the review @shanejonas! Just had to rebase this to resolve conflicts. The diff should be identical now except for the tests, which now need "V4" specified explicitly in a few places due to the consolidation PR that was merged.

@Gudahtt Gudahtt mentioned this pull request Jul 27, 2021
@Gudahtt Gudahtt force-pushed the allow-sign-typed-data-utilties-to-be-called-unbound branch from d1b3605 to cf0663c Compare August 2, 2021 15:14
Previously the functions exposed as `TypedDataUtils` could only be
called from the `TypedDataUtils` object. If they were called unbound,
they would throw errors because of the use of `this`.

They have all been updated to no longer rely upon `this`, so they now
work the same way regardless how they are bound when called.

They are still exported as the `TypedDataUtils` object, so this should
not change the API. This was done to simplify the code, specifically to
make it easier for functions outside of `TypedDataUtils` to reuse code
inside of `TypedDataUtils`.

Some types required adjustments, as type mistakes were brought to light
that TypeScript for some reason wasn't aware of when these were
declared as properties of the `TypedDataUtils` object. These were fixed
by adding two type assertions, making the `types` parameter to
`hashStruct` and `hashType` more strict, and by making the `typedData`
parameter to `eip712Hash` more strict. The type assertions (warranted
or not) preserve the types used previously. We can replace them later
with validation.
@Gudahtt Gudahtt force-pushed the allow-sign-typed-data-utilties-to-be-called-unbound branch from 00a876d to 807aeae Compare August 2, 2021 15:18
@Gudahtt Gudahtt merged commit 0c7e95a into main Aug 3, 2021
@Gudahtt Gudahtt deleted the allow-sign-typed-data-utilties-to-be-called-unbound branch August 3, 2021 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants