import { schemas, SchemaValidator } from '@0xproject/json-schemas'; import { Order, SignedOrder } from '@0xproject/types'; import * as _ from 'lodash'; import { assert } from './assert'; 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. * 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, [schemas.hexSchema]); } 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; } const orderHashBuff = orderHashUtils.getOrderHashBuffer(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 */ getOrderHashBuffer(order: SignedOrder | Order): Buffer { const orderParamsHashBuff = EIP712Utils.structHash(EIP712_ORDER_SCHEMA, order); const orderHashBuff = EIP712Utils.createEIP712Message(orderParamsHashBuff, order.exchangeAddress); return orderHashBuff; }, _getOrderSchemaBuffer(): Buffer { return EIP712Utils.compileSchema(EIP712_ORDER_SCHEMA); }, };