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.ts89
1 files changed, 89 insertions, 0 deletions
diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts
new file mode 100644
index 000000000..8da11c596
--- /dev/null
+++ b/packages/order-utils/src/order_hash.ts
@@ -0,0 +1,89 @@
+import { schemas, SchemaValidator } from '@0xproject/json-schemas';
+import { Order, SignedOrder, SolidityTypes } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import BN = require('bn.js');
+import * as ethABI from 'ethereumjs-abi';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { assert } from './assert';
+
+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) {
+ return new BN(value.toString(), 10);
+}
+
+/**
+ * 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);
+ }
+ 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;
+}