-
-
Notifications
You must be signed in to change notification settings - Fork 229
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
Fix typed message schema mistake #243
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,232 @@ | ||
import * as ethUtil from 'ethereumjs-util'; | ||
import Ajv from 'ajv'; | ||
import { | ||
recoverTypedSignature, | ||
signTypedData, | ||
TypedDataUtils, | ||
typedSignatureHash, | ||
SignTypedDataVersion, | ||
TYPED_MESSAGE_SCHEMA, | ||
} from './sign-typed-data'; | ||
|
||
const privateKey = Buffer.from( | ||
'4af1bceebf7f3634ec3cff8a2c38e51178d5d4ce585c52d6043e5e2cc3418bb0', | ||
'hex', | ||
); | ||
|
||
/** | ||
* Get a list of all Solidity types supported by EIP-712. | ||
* | ||
* @returns A list of all supported Solidity types. | ||
*/ | ||
function getEip712SolidityTypes() { | ||
const types = ['bool', 'address', 'string', 'bytes']; | ||
const ints = Array.from(new Array(32)).map( | ||
(_, index) => `int${(index + 1) * 8}`, | ||
); | ||
const uints = Array.from(new Array(32)).map( | ||
(_, index) => `uint${(index + 1) * 8}`, | ||
); | ||
const bytes = Array.from(new Array(32)).map( | ||
(_, index) => `bytes${index + 1}`, | ||
); | ||
|
||
return [...types, ...ints, ...uints, ...bytes]; | ||
} | ||
|
||
const eip712SolidityTypes = getEip712SolidityTypes(); | ||
|
||
describe('TYPED_MESSAGE_SCHEMA', () => { | ||
it('should match valid typed message', () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'object', | ||
types: { | ||
EIP712Domain: [], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(true); | ||
}); | ||
|
||
it('should allow custom types in addition to domain', () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'Message', | ||
types: { | ||
EIP712Domain: [], | ||
Message: [], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(true); | ||
}); | ||
|
||
for (const solidityType of eip712SolidityTypes) { | ||
// eslint-disable-next-line no-loop-func | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] If you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does, but now that you've brought this up, I kinda want to get to the bottom of this. This ought to work. Something is messed up with the ESLint globals configuration. I'll look into this in a subsequent PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh my goodness. I found the problem. The override for the test ESLint config is wrong, the file glob uses the Edit: Done in #245 |
||
it(`should allow custom type to have type of '${solidityType}'`, () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'Message', | ||
types: { | ||
EIP712Domain: [], | ||
Message: [{ name: 'data', type: solidityType }], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(true); | ||
}); | ||
} | ||
|
||
it('should allow custom type to have a custom type', () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'Message', | ||
types: { | ||
CustomValue: [{ name: 'value', type: 'string' }], | ||
EIP712Domain: [], | ||
Message: [{ name: 'data', type: 'CustomValue' }], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(true); | ||
}); | ||
|
||
const invalidStrings = [undefined, null, 0, 1, [], {}]; | ||
|
||
for (const invalidString of invalidStrings) { | ||
// eslint-disable-next-line no-loop-func | ||
it(`should disallow a primary type with value '${invalidString}'`, () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: invalidString, | ||
types: { | ||
EIP712Domain: [], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
} | ||
|
||
const invalidObjects = [undefined, null, 0, 1, [], '', 'test']; | ||
for (const invalidObject of invalidObjects) { | ||
// eslint-disable-next-line no-loop-func | ||
it(`should disallow a domain with value '${invalidObject}'`, () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: invalidObject, | ||
message: {}, | ||
primaryType: 'object', | ||
types: { | ||
EIP712Domain: [], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
|
||
// eslint-disable-next-line no-loop-func | ||
it(`should disallow a message with value '${invalidObject}'`, () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: invalidObject, | ||
primaryType: 'object', | ||
types: { | ||
EIP712Domain: [], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
|
||
// eslint-disable-next-line no-loop-func | ||
it(`should disallow types with value '${invalidObject}'`, () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'object', | ||
types: invalidObject, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
} | ||
|
||
it('should require custom type properties to have a name', () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'Message', | ||
types: { | ||
EIP712Domain: [], | ||
Message: [{ type: 'string' }], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
|
||
it('should require custom type properties to have a type', () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'Message', | ||
types: { | ||
EIP712Domain: [], | ||
Message: [{ name: 'name' }], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
|
||
const invalidTypes = [undefined, null, 0, 1, [], {}]; | ||
|
||
for (const invalidType of invalidTypes) { | ||
// eslint-disable-next-line no-loop-func | ||
it(`should disallow a type of '${invalidType}'`, () => { | ||
const ajv = new Ajv(); | ||
const validate = ajv.compile(TYPED_MESSAGE_SCHEMA); | ||
const typedMessage = { | ||
domain: {}, | ||
message: {}, | ||
primaryType: 'Message', | ||
types: { | ||
EIP712Domain: [], | ||
Message: [{ name: 'name', type: invalidType }], | ||
}, | ||
}; | ||
|
||
expect(validate(typedMessage)).toBe(false); | ||
}); | ||
} | ||
}); | ||
|
||
const encodeDataExamples = { | ||
// dynamic types supported by EIP-712: | ||
bytes: [10, '10', '0x10', Buffer.from('10', 'utf8')], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] What do you think about extracting this
validate
function since it's the same for every test?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! Done in b5f0d87