aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src/order_hash.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils/src/order_hash.ts')
-rw-r--r--packages/order-utils/src/order_hash.ts180
1 files changed, 103 insertions, 77 deletions
diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts
index 108344a04..3d0db5b0c 100644
--- a/packages/order-utils/src/order_hash.ts
+++ b/packages/order-utils/src/order_hash.ts
@@ -1,5 +1,5 @@
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
-import { Order, SignedOrder, SolidityTypes } from '@0xproject/types';
+import { Order, SignatureType, SignedOrder, SolidityTypes } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import BN = require('bn.js');
import * as ethABI from 'ethereumjs-abi';
@@ -7,84 +7,110 @@ import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { assert } from './assert';
+import { crypto } from './crypto';
const INVALID_TAKER_FORMAT = 'instance.taker is not of a type(s) string';
-/**
- * Converts BigNumber instance to BN
- * The only reason we convert to BN is to remain compatible with `ethABI.soliditySHA3` that
- * expects values of Solidity type `uint` to be passed as type `BN`.
- * We do not use BN anywhere else in the codebase.
- */
-function bigNumberToBN(value: BigNumber): BN {
- const base = 10;
- return new BN(value.toString(), base);
-}
-
-/**
- * Computes the orderHash for a supplied order.
- * @param order An object that conforms to the Order or SignedOrder interface definitions.
- * @return The resulting orderHash from hashing the supplied order.
- */
-export function getOrderHashHex(order: Order | SignedOrder): string {
- try {
- assert.doesConformToSchema('order', order, schemas.orderSchema);
- } catch (error) {
- if (_.includes(error.message, INVALID_TAKER_FORMAT)) {
- const errMsg =
- 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
- throw new Error(errMsg);
+export const orderHashUtils = {
+ /**
+ * Checks if the supplied hex encoded order hash is valid.
+ * Note: Valid means it has the expected format, not that an order with the orderHash exists.
+ * Use this method when processing orderHashes submitted as user input.
+ * @param orderHash Hex encoded orderHash.
+ * @return Whether the supplied orderHash has the expected format.
+ */
+ isValidOrderHash(orderHash: string): boolean {
+ // Since this method can be called to check if any arbitrary string conforms to an orderHash's
+ // format, we only assert that we were indeed passed a string.
+ assert.isString('orderHash', orderHash);
+ const schemaValidator = new SchemaValidator();
+ const isValid = schemaValidator.validate(orderHash, schemas.orderHashSchema).valid;
+ return isValid;
+ },
+ /**
+ * Computes the orderHash for a supplied order.
+ * @param order An object that conforms to the Order or SignedOrder interface definitions.
+ * @return The resulting orderHash from hashing the supplied order.
+ */
+ getOrderHashHex(order: SignedOrder | Order): string {
+ try {
+ assert.doesConformToSchema('order', order, schemas.orderSchema);
+ } catch (error) {
+ if (_.includes(error.message, INVALID_TAKER_FORMAT)) {
+ const errMsg =
+ 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
+ throw new Error(errMsg);
+ }
+ throw error;
}
- throw error;
- }
- const orderParts = [
- { value: order.exchangeContractAddress, type: SolidityTypes.Address },
- { value: order.maker, type: SolidityTypes.Address },
- { value: order.taker, type: SolidityTypes.Address },
- { value: order.makerTokenAddress, type: SolidityTypes.Address },
- { value: order.takerTokenAddress, type: SolidityTypes.Address },
- { value: order.feeRecipient, type: SolidityTypes.Address },
- {
- value: bigNumberToBN(order.makerTokenAmount),
- type: SolidityTypes.Uint256,
- },
- {
- value: bigNumberToBN(order.takerTokenAmount),
- type: SolidityTypes.Uint256,
- },
- {
- value: bigNumberToBN(order.makerFee),
- type: SolidityTypes.Uint256,
- },
- {
- value: bigNumberToBN(order.takerFee),
- type: SolidityTypes.Uint256,
- },
- {
- value: bigNumberToBN(order.expirationUnixTimestampSec),
- type: SolidityTypes.Uint256,
- },
- { value: bigNumberToBN(order.salt), type: SolidityTypes.Uint256 },
- ];
- const types = _.map(orderParts, o => o.type);
- const values = _.map(orderParts, o => o.value);
- const hashBuff = ethABI.soliditySHA3(types, values);
- const hashHex = ethUtil.bufferToHex(hashBuff);
- return hashHex;
-}
-/**
- * Checks if the supplied hex encoded order hash is valid.
- * Note: Valid means it has the expected format, not that an order with the orderHash exists.
- * Use this method when processing orderHashes submitted as user input.
- * @param orderHash Hex encoded orderHash.
- * @return Whether the supplied orderHash has the expected format.
- */
-export function isValidOrderHash(orderHash: string): boolean {
- // Since this method can be called to check if any arbitrary string conforms to an orderHash's
- // format, we only assert that we were indeed passed a string.
- assert.isString('orderHash', orderHash);
- const schemaValidator = new SchemaValidator();
- const isValid = schemaValidator.validate(orderHash, schemas.orderHashSchema).valid;
- return isValid;
-}
+ const orderHashBuff = this.getOrderHashBuff(order);
+ const orderHashHex = `0x${orderHashBuff.toString('hex')}`;
+ return orderHashHex;
+ },
+ /**
+ * Computes the orderHash for a supplied order and returns it as a Buffer
+ * @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),
+ ]);
+ 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;
+ },
+};