aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src/eip712_utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils/src/eip712_utils.ts')
-rw-r--r--packages/order-utils/src/eip712_utils.ts162
1 files changed, 68 insertions, 94 deletions
diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts
index b303c93dc..56f736500 100644
--- a/packages/order-utils/src/eip712_utils.ts
+++ b/packages/order-utils/src/eip712_utils.ts
@@ -1,109 +1,83 @@
-import ethUtil = require('ethereumjs-util');
+import { assert } from '@0xproject/assert';
+import { schemas } from '@0xproject/json-schemas';
+import { EIP712Object, EIP712TypedData, EIP712Types, Order, ZeroExTransaction } from '@0xproject/types';
import * as _ from 'lodash';
-import { crypto } from './crypto';
-import { EIP712Schema, EIP712Types } from './types';
-
-const EIP191_PREFIX = '\x19\x01';
-const EIP712_DOMAIN_NAME = '0x Protocol';
-const EIP712_DOMAIN_VERSION = '2';
-const EIP712_VALUE_LENGTH = 32;
-
-const EIP712_DOMAIN_SCHEMA: EIP712Schema = {
- name: 'EIP712Domain',
- parameters: [
- { name: 'name', type: EIP712Types.String },
- { name: 'version', type: EIP712Types.String },
- { name: 'verifyingContract', type: EIP712Types.Address },
- ],
-};
+import { constants } from './constants';
export const eip712Utils = {
/**
- * Compiles the EIP712Schema and returns the hash of the schema.
- * @param schema The EIP712 schema.
- * @return The hash of the compiled schema
- */
- compileSchema(schema: EIP712Schema): Buffer {
- const eip712Schema = eip712Utils._encodeType(schema);
- const eip712SchemaHashBuffer = crypto.solSHA3([eip712Schema]);
- return eip712SchemaHashBuffer;
- },
- /**
- * Merges the EIP712 hash of a struct with the DomainSeparator for 0x v2.
- * @param hashStruct the EIP712 hash of a struct
- * @param contractAddress the exchange contract address
- * @return The hash of an EIP712 message with domain separator prefixed
- */
- createEIP712Message(hashStruct: Buffer, contractAddress: string): Buffer {
- const domainSeparatorHashBuffer = eip712Utils._getDomainSeparatorHashBuffer(contractAddress);
- const messageBuff = crypto.solSHA3([EIP191_PREFIX, domainSeparatorHashBuffer, hashStruct]);
- return messageBuff;
- },
- /**
- * Pad an address to 32 bytes
- * @param address Address to pad
- * @return padded address
+ * Creates a EIP712TypedData object specific to the 0x protocol for use with signTypedData.
+ * @param primaryType The primary type found in message
+ * @param types The additional types for the data in message
+ * @param message The contents of the message
+ * @param exchangeAddress The address of the exchange contract
+ * @return A typed data object
*/
- pad32Address(address: string): Buffer {
- const addressBuffer = ethUtil.toBuffer(address);
- const addressPadded = eip712Utils.pad32Buffer(addressBuffer);
- return addressPadded;
+ createTypedData: (
+ primaryType: string,
+ types: EIP712Types,
+ message: EIP712Object,
+ exchangeAddress: string,
+ ): EIP712TypedData => {
+ assert.isETHAddressHex('exchangeAddress', exchangeAddress);
+ assert.isString('primaryType', primaryType);
+ const typedData = {
+ types: {
+ EIP712Domain: constants.EIP712_DOMAIN_SCHEMA.parameters,
+ ...types,
+ },
+ domain: {
+ name: constants.EIP712_DOMAIN_NAME,
+ version: constants.EIP712_DOMAIN_VERSION,
+ verifyingContract: exchangeAddress,
+ },
+ message,
+ primaryType,
+ };
+ assert.doesConformToSchema('typedData', typedData, schemas.eip712TypedDataSchema);
+ return typedData;
},
/**
- * Pad an buffer to 32 bytes
- * @param buffer Address to pad
- * @return padded buffer
+ * Creates an Order EIP712TypedData object for use with signTypedData.
+ * @param Order the order
+ * @return A typed data object
*/
- pad32Buffer(buffer: Buffer): Buffer {
- const bufferPadded = ethUtil.setLengthLeft(buffer, EIP712_VALUE_LENGTH);
- return bufferPadded;
+ createOrderTypedData: (order: Order): EIP712TypedData => {
+ assert.doesConformToSchema('order', order, schemas.orderSchema, [schemas.hexSchema]);
+ const normalizedOrder = _.mapValues(order, value => {
+ return !_.isString(value) ? value.toString() : value;
+ });
+ const typedData = eip712Utils.createTypedData(
+ constants.EIP712_ORDER_SCHEMA.name,
+ { Order: constants.EIP712_ORDER_SCHEMA.parameters },
+ normalizedOrder,
+ order.exchangeAddress,
+ );
+ return typedData;
},
/**
- * Hash together a EIP712 schema with the corresponding data
- * @param schema EIP712-compliant schema
- * @param data Data the complies to the schema
- * @return A buffer containing the SHA256 hash of the schema and encoded data
+ * Creates an ExecuteTransaction EIP712TypedData object for use with signTypedData and
+ * 0x Exchange executeTransaction.
+ * @param ZeroExTransaction the 0x transaction
+ * @param exchangeAddress The address of the exchange contract
+ * @return A typed data object
*/
- structHash(schema: EIP712Schema, data: { [key: string]: any }): Buffer {
- const encodedData = eip712Utils._encodeData(schema, data);
- const schemaHash = eip712Utils.compileSchema(schema);
- const hashBuffer = crypto.solSHA3([schemaHash, ...encodedData]);
- return hashBuffer;
- },
- _getDomainSeparatorSchemaBuffer(): Buffer {
- return eip712Utils.compileSchema(EIP712_DOMAIN_SCHEMA);
- },
- _getDomainSeparatorHashBuffer(exchangeAddress: string): Buffer {
- const domainSeparatorSchemaBuffer = eip712Utils._getDomainSeparatorSchemaBuffer();
- const encodedData = eip712Utils._encodeData(EIP712_DOMAIN_SCHEMA, {
- name: EIP712_DOMAIN_NAME,
- version: EIP712_DOMAIN_VERSION,
- verifyingContract: exchangeAddress,
+ createZeroExTransactionTypedData: (
+ zeroExTransaction: ZeroExTransaction,
+ exchangeAddress: string,
+ ): EIP712TypedData => {
+ assert.isETHAddressHex('exchangeAddress', exchangeAddress);
+ assert.doesConformToSchema('zeroExTransaction', zeroExTransaction, schemas.zeroExTransactionSchema);
+ const normalizedTransaction = _.mapValues(zeroExTransaction, value => {
+ return !_.isString(value) ? value.toString() : value;
});
- const domainSeparatorHashBuff2 = crypto.solSHA3([domainSeparatorSchemaBuffer, ...encodedData]);
- return domainSeparatorHashBuff2;
- },
- _encodeType(schema: EIP712Schema): string {
- const namedTypes = _.map(schema.parameters, ({ name, type }) => `${type} ${name}`);
- const namedTypesJoined = namedTypes.join(',');
- const encodedType = `${schema.name}(${namedTypesJoined})`;
- return encodedType;
- },
- _encodeData(schema: EIP712Schema, data: { [key: string]: any }): any {
- const encodedValues = [];
- for (const parameter of schema.parameters) {
- const value = data[parameter.name];
- if (parameter.type === EIP712Types.String || parameter.type === EIP712Types.Bytes) {
- encodedValues.push(crypto.solSHA3([ethUtil.toBuffer(value)]));
- } else if (parameter.type === EIP712Types.Uint256) {
- encodedValues.push(value);
- } else if (parameter.type === EIP712Types.Address) {
- encodedValues.push(eip712Utils.pad32Address(value));
- } else {
- throw new Error(`Unable to encode ${parameter.type}`);
- }
- }
- return encodedValues;
+ const typedData = eip712Utils.createTypedData(
+ constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.name,
+ { ZeroExTransaction: constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.parameters },
+ normalizedTransaction,
+ exchangeAddress,
+ );
+ return typedData;
},
};