aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-06-20 19:25:29 +0800
committerFabio Berger <me@fabioberger.com>2018-06-20 19:25:29 +0800
commit2ffab2218584fac5d3ea2b264a7c746d963083d9 (patch)
treef7558147b811c06300e2c7697591466ae7cf48ba /packages/order-utils/src
parent5541327968ad6f974a37c49057253746f738a709 (diff)
parent096eaa20d785baee07b06b3f0848797e470fbda0 (diff)
downloaddexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.tar
dexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.tar.gz
dexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.tar.bz2
dexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.tar.lz
dexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.tar.xz
dexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.tar.zst
dexon-sol-tools-2ffab2218584fac5d3ea2b264a7c746d963083d9.zip
Merge branch 'v2-prototype' into feature/combinatorial-testing
* v2-prototype: (22 commits) Fix closing parens in liborder Update after rebase ERC721Proxy Always call safeTransferFrom Rename makerEpoch => orderEpoch Make cancelOrdersUpTo compatible with sender abstraction Update PR template Use Image component instead of img tag Assembler orderHash function Optimize and remove redundant encodePacked Fix linting issue Fix bug where we do fetch balances on wallet login Check network state immediately instead of waiting for delay Fix onboarding persisting when changing routes Consolidate account state messaging logic Only elevate wallet zIndex when onboarding is in progress Rebase and update feedback Run linter Add Portal v2 logging Simplified handling of source < 32 edge case Basic EIP712 encoder ...
Diffstat (limited to 'packages/order-utils/src')
-rw-r--r--packages/order-utils/src/eip712_utils.ts93
-rw-r--r--packages/order-utils/src/index.ts3
-rw-r--r--packages/order-utils/src/order_hash.ts87
-rw-r--r--packages/order-utils/src/types.ts18
4 files changed, 139 insertions, 62 deletions
diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts
new file mode 100644
index 000000000..2594e6d6d
--- /dev/null
+++ b/packages/order-utils/src/eip712_utils.ts
@@ -0,0 +1,93 @@
+import ethUtil = require('ethereumjs-util');
+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 },
+ ],
+};
+
+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;
+ },
+ pad32Address(address: string): Buffer {
+ const addressBuffer = ethUtil.toBuffer(address);
+ const addressPadded = EIP712Utils.pad32Buffer(addressBuffer);
+ return addressPadded;
+ },
+ pad32Buffer(buffer: Buffer): Buffer {
+ const bufferPadded = ethUtil.setLengthLeft(buffer, EIP712_VALUE_LENGTH);
+ return bufferPadded;
+ },
+ _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,
+ });
+ 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;
+ },
+ 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;
+ },
+};
diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts
index 592b9b7f6..b4a7a6b67 100644
--- a/packages/order-utils/src/index.ts
+++ b/packages/order-utils/src/index.ts
@@ -13,12 +13,13 @@ export { orderFactory } from './order_factory';
export { constants } from './constants';
export { crypto } from './crypto';
export { generatePseudoRandomSalt } from './salt';
-export { OrderError, MessagePrefixType, MessagePrefixOpts } from './types';
+export { OrderError, MessagePrefixType, MessagePrefixOpts, EIP712Parameter, EIP712Schema, EIP712Types } from './types';
export { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
export { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
export { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store';
export { RemainingFillableCalculator } from './remaining_fillable_calculator';
export { OrderStateUtils } from './order_state_utils';
export { assetProxyUtils } from './asset_proxy_utils';
+export { EIP712Utils } from './eip712_utils';
export { OrderValidationUtils } from './order_validation_utils';
export { ExchangeTransferSimulator } from './exchange_transfer_simulator';
diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts
index b9d0b43aa..54c500653 100644
--- a/packages/order-utils/src/order_hash.ts
+++ b/packages/order-utils/src/order_hash.ts
@@ -1,14 +1,31 @@
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
import { Order, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { assert } from './assert';
-import { crypto } from './crypto';
+import { EIP712Utils } from './eip712_utils';
+import { EIP712Schema, EIP712Types } from './types';
const INVALID_TAKER_FORMAT = 'instance.takerAddress is not of a type(s) string';
+const EIP712_ORDER_SCHEMA: EIP712Schema = {
+ name: 'Order',
+ parameters: [
+ { name: 'makerAddress', type: EIP712Types.Address },
+ { name: 'takerAddress', type: EIP712Types.Address },
+ { name: 'feeRecipientAddress', type: EIP712Types.Address },
+ { name: 'senderAddress', type: EIP712Types.Address },
+ { name: 'makerAssetAmount', type: EIP712Types.Uint256 },
+ { name: 'takerAssetAmount', type: EIP712Types.Uint256 },
+ { name: 'makerFee', type: EIP712Types.Uint256 },
+ { name: 'takerFee', type: EIP712Types.Uint256 },
+ { name: 'expirationTimeSeconds', type: EIP712Types.Uint256 },
+ { name: 'salt', type: EIP712Types.Uint256 },
+ { name: 'makerAssetData', type: EIP712Types.Bytes },
+ { name: 'takerAssetData', type: EIP712Types.Bytes },
+ ],
+};
+
export const orderHashUtils = {
/**
* Checks if the supplied hex encoded order hash is valid.
@@ -42,7 +59,7 @@ export const orderHashUtils = {
throw error;
}
- const orderHashBuff = this.getOrderHashBuff(order);
+ const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
const orderHashHex = `0x${orderHashBuff.toString('hex')}`;
return orderHashHex;
},
@@ -51,64 +68,12 @@ export const orderHashUtils = {
* @param order An object that conforms to the Order or SignedOrder interface definitions.
* @return The resulting orderHash from hashing the supplied order as a Buffer
*/
- getOrderHashBuff(order: SignedOrder | Order): Buffer {
- const makerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.makerAssetData)]);
- const takerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.takerAssetData)]);
-
- const orderParamsHashBuff = crypto.solSHA3([
- order.makerAddress,
- order.takerAddress,
- order.feeRecipientAddress,
- order.senderAddress,
- order.makerAssetAmount,
- order.takerAssetAmount,
- order.makerFee,
- order.takerFee,
- order.expirationTimeSeconds,
- order.salt,
- makerAssetDataHash,
- takerAssetDataHash,
- ]);
- const orderParamsHashHex = `0x${orderParamsHashBuff.toString('hex')}`;
- const orderSchemaHashHex = this._getOrderSchemaHex();
- const domainSeparatorHashHex = this._getDomainSeparatorHashHex(order.exchangeAddress);
- const domainSeparatorSchemaHex = this._getDomainSeparatorSchemaHex();
- const orderHashBuff = crypto.solSHA3([
- new BigNumber(domainSeparatorSchemaHex),
- new BigNumber(domainSeparatorHashHex),
- new BigNumber(orderSchemaHashHex),
- new BigNumber(orderParamsHashHex),
- ]);
+ getOrderHashBuffer(order: SignedOrder | Order): Buffer {
+ const orderParamsHashBuff = EIP712Utils.structHash(EIP712_ORDER_SCHEMA, order);
+ const orderHashBuff = EIP712Utils.createEIP712Message(orderParamsHashBuff, order.exchangeAddress);
return orderHashBuff;
},
- _getOrderSchemaHex(): string {
- const orderSchemaHashBuff = crypto.solSHA3([
- 'Order(',
- 'address makerAddress,',
- 'address takerAddress,',
- 'address feeRecipientAddress,',
- 'address senderAddress,',
- 'uint256 makerAssetAmount,',
- 'uint256 takerAssetAmount,',
- 'uint256 makerFee,',
- 'uint256 takerFee,',
- 'uint256 expirationTimeSeconds,',
- 'uint256 salt,',
- 'bytes makerAssetData,',
- 'bytes takerAssetData,',
- ')',
- ]);
- const schemaHashHex = `0x${orderSchemaHashBuff.toString('hex')}`;
- return schemaHashHex;
- },
- _getDomainSeparatorSchemaHex(): string {
- const domainSeparatorSchemaHashBuff = crypto.solSHA3(['DomainSeparator(address contract)']);
- const schemaHashHex = `0x${domainSeparatorSchemaHashBuff.toString('hex')}`;
- return schemaHashHex;
- },
- _getDomainSeparatorHashHex(exchangeAddress: string): string {
- const domainSeparatorHashBuff = crypto.solSHA3([exchangeAddress]);
- const domainSeparatorHashHex = `0x${domainSeparatorHashBuff.toString('hex')}`;
- return domainSeparatorHashHex;
+ _getOrderSchemaBuffer(): Buffer {
+ return EIP712Utils.compileSchema(EIP712_ORDER_SCHEMA);
},
};
diff --git a/packages/order-utils/src/types.ts b/packages/order-utils/src/types.ts
index 3f1fce66d..b08e74e71 100644
--- a/packages/order-utils/src/types.ts
+++ b/packages/order-utils/src/types.ts
@@ -33,3 +33,21 @@ export enum TransferType {
Trade = 'trade',
Fee = 'fee',
}
+
+export interface EIP712Parameter {
+ name: string;
+ type: EIP712Types;
+}
+
+export interface EIP712Schema {
+ name: string;
+ parameters: EIP712Parameter[];
+}
+
+export enum EIP712Types {
+ Address = 'address',
+ Bytes = 'bytes',
+ Bytes32 = 'bytes32',
+ String = 'string',
+ Uint256 = 'uint256',
+}