diff options
author | Fabio Berger <me@fabioberger.com> | 2018-05-30 07:58:30 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-05-30 07:58:30 +0800 |
commit | 4874d55d03918b47967024777194d88a5f2bc1fc (patch) | |
tree | 4a53834e9424a8b33aa7d0edaf13de11f2e807a3 /packages/order-utils/src/order_hash.ts | |
parent | 10faa474950a902af943b3c51f3703491afa6520 (diff) | |
download | dexon-sol-tools-4874d55d03918b47967024777194d88a5f2bc1fc.tar.gz dexon-sol-tools-4874d55d03918b47967024777194d88a5f2bc1fc.tar.zst dexon-sol-tools-4874d55d03918b47967024777194d88a5f2bc1fc.zip |
Initial refactor of order-utils. Move many utils from contracts into this package.
Diffstat (limited to 'packages/order-utils/src/order_hash.ts')
-rw-r--r-- | packages/order-utils/src/order_hash.ts | 180 |
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; + }, +}; |