diff options
Diffstat (limited to 'packages/order-utils')
-rw-r--r-- | packages/order-utils/CHANGELOG.json | 32 | ||||
-rw-r--r-- | packages/order-utils/CHANGELOG.md | 15 | ||||
-rw-r--r-- | packages/order-utils/package.json | 27 | ||||
-rw-r--r-- | packages/order-utils/src/constants.ts | 10 | ||||
-rw-r--r-- | packages/order-utils/src/eip712_utils.ts | 49 | ||||
-rw-r--r-- | packages/order-utils/src/index.ts | 3 | ||||
-rw-r--r-- | packages/order-utils/src/order_hash.ts | 17 | ||||
-rw-r--r-- | packages/order-utils/src/signature_utils.ts | 10 | ||||
-rw-r--r-- | packages/order-utils/src/transaction_hash.ts | 46 | ||||
-rw-r--r-- | packages/order-utils/test/eip712_utils_test.ts | 48 | ||||
-rw-r--r-- | packages/order-utils/test/order_hash_test.ts | 5 | ||||
-rw-r--r-- | packages/order-utils/test/signature_utils_test.ts | 11 | ||||
-rw-r--r-- | packages/order-utils/test/transaction_hash_test.ts | 56 |
13 files changed, 272 insertions, 57 deletions
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 08d88da5b..d58a8a4c2 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,12 +1,42 @@ [ { + "version": "6.0.0", + "changes": { + "note": "Stop exporting the EIP712 schemas" + }, + "timestamp": 1549504360 + }, + { + "version": "5.0.0", + "changes": [ + { + "note": "Add `transactionHashUtils`", + "pr": 1576 + }, + { + "note": "Refactor `eip712Utils` to allow custom domain params", + "pr": 1576 + }, + { + "note": "Export constant EIP712 params", + "pr": 1576 + } + ], + "timestamp": 1549452781 + }, + { "version": "4.0.0", "changes": [ { "note": "Upgrade the bignumber.js to v8.0.2", "pr": 1517 + }, + { + "note": "Fix preSigned `isSignatureValidAsync` check", + "pr": 1580 } - ] + ], + "timestamp": 1549373905 }, { "timestamp": 1547561734, diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md index c82458f2e..f5e20a8d8 100644 --- a/packages/order-utils/CHANGELOG.md +++ b/packages/order-utils/CHANGELOG.md @@ -5,6 +5,21 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.0.0 - _February 7, 2019_ + + * undefined + +## v5.0.0 - _February 6, 2019_ + + * Add `transactionHashUtils` (#1576) + * Refactor `eip712Utils` to allow custom domain params (#1576) + * Export constant EIP712 params (#1576) + +## v4.0.0 - _February 5, 2019_ + + * Upgrade the bignumber.js to v8.0.2 (#1517) + * Fix preSigned `isSignatureValidAsync` check (#1580) + ## v3.1.2 - _January 15, 2019_ * Dependencies updated diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index 7a4d4aa84..90fdfeed3 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/order-utils", - "version": "3.1.2", + "version": "6.0.0", "engines": { "node": ">=6.12" }, @@ -35,8 +35,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md", "devDependencies": { - "@0x/dev-utils": "^1.0.24", - "@0x/tslint-config": "^2.0.2", + "@0x/dev-utils": "^2.0.1", + "@0x/tslint-config": "^3.0.0", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", "chai": "^4.0.1", @@ -53,22 +53,23 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^2.2.0", - "@0x/assert": "^1.0.23", - "@0x/base-contract": "^3.0.13", + "@0x/abi-gen-wrappers": "^3.0.1", + "@0x/assert": "^2.0.1", + "@0x/base-contract": "^4.0.1", + "@0x/contract-addresses": "^2.2.1", "@0x/contract-artifacts": "^1.3.0", - "@0x/json-schemas": "^2.1.7", - "@0x/types": "^1.5.2", - "@0x/typescript-typings": "^3.0.8", - "@0x/utils": "^3.0.1", - "@0x/web3-wrapper": "^3.2.4", + "@0x/json-schemas": "^3.0.1", + "@0x/types": "^2.0.1", + "@0x/typescript-typings": "^4.0.0", + "@0x/utils": "^4.0.2", + "@0x/web3-wrapper": "^4.0.1", "@types/node": "*", "bn.js": "^4.11.8", - "ethereum-types": "^1.1.6", + "ethereum-types": "^2.0.0", "ethereumjs-abi": "0.6.5", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", - "lodash": "^4.17.5" + "lodash": "^4.17.11" }, "publishConfig": { "access": "public" diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts index a9a687719..3c93575b3 100644 --- a/packages/order-utils/src/constants.ts +++ b/packages/order-utils/src/constants.ts @@ -68,9 +68,9 @@ export const constants = { SELECTOR_CHAR_LENGTH_WITH_PREFIX: 10, INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite ZERO_AMOUNT: new BigNumber(0), - EIP712_DOMAIN_NAME: '0x Protocol', - EIP712_DOMAIN_VERSION: '2', - EIP712_DOMAIN_SCHEMA: { + EXCHANGE_DOMAIN_NAME: '0x Protocol', + EXCHANGE_DOMAIN_VERSION: '2', + DEFAULT_DOMAIN_SCHEMA: { name: 'EIP712Domain', parameters: [ { name: 'name', type: 'string' }, @@ -78,7 +78,7 @@ export const constants = { { name: 'verifyingContract', type: 'address' }, ], }, - EIP712_ORDER_SCHEMA: { + EXCHANGE_ORDER_SCHEMA: { name: 'Order', parameters: [ { name: 'makerAddress', type: 'address' }, @@ -95,7 +95,7 @@ export const constants = { { name: 'takerAssetData', type: 'bytes' }, ], }, - EIP712_ZEROEX_TRANSACTION_SCHEMA: { + EXCHANGE_ZEROEX_TRANSACTION_SCHEMA: { name: 'ZeroExTransaction', parameters: [ { name: 'salt', type: 'uint256' }, diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts index 385fda989..685fdc8c8 100644 --- a/packages/order-utils/src/eip712_utils.ts +++ b/packages/order-utils/src/eip712_utils.ts @@ -1,6 +1,13 @@ import { assert } from '@0x/assert'; import { schemas } from '@0x/json-schemas'; -import { EIP712Object, EIP712TypedData, EIP712Types, Order, ZeroExTransaction } from '@0x/types'; +import { + EIP712DomainWithDefaultSchema, + EIP712Object, + EIP712TypedData, + EIP712Types, + Order, + ZeroExTransaction, +} from '@0x/types'; import * as _ from 'lodash'; import { constants } from './constants'; @@ -11,26 +18,26 @@ export const eip712Utils = { * @param primaryType The primary type found in message * @param types The additional types for the data in message * @param message The contents of the message - * @param exchangeAddress The address of the exchange contract + * @param domain Domain containing a name (optional), version (optional), and verifying contract address * @return A typed data object */ createTypedData: ( primaryType: string, types: EIP712Types, message: EIP712Object, - exchangeAddress: string, + domain: EIP712DomainWithDefaultSchema, ): EIP712TypedData => { - assert.isETHAddressHex('exchangeAddress', exchangeAddress); + assert.isETHAddressHex('verifyingContractAddress', domain.verifyingContractAddress); assert.isString('primaryType', primaryType); const typedData = { types: { - EIP712Domain: constants.EIP712_DOMAIN_SCHEMA.parameters, + EIP712Domain: constants.DEFAULT_DOMAIN_SCHEMA.parameters, ...types, }, domain: { - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - verifyingContract: exchangeAddress, + name: _.isUndefined(domain.name) ? constants.EXCHANGE_DOMAIN_NAME : domain.name, + version: _.isUndefined(domain.version) ? constants.EXCHANGE_DOMAIN_VERSION : domain.version, + verifyingContract: domain.verifyingContractAddress, }, message, primaryType, @@ -48,11 +55,14 @@ export const eip712Utils = { const normalizedOrder = _.mapValues(order, value => { return !_.isString(value) ? value.toString() : value; }); + const domain = { + verifyingContractAddress: order.exchangeAddress, + }; const typedData = eip712Utils.createTypedData( - constants.EIP712_ORDER_SCHEMA.name, - { Order: constants.EIP712_ORDER_SCHEMA.parameters }, + constants.EXCHANGE_ORDER_SCHEMA.name, + { Order: constants.EXCHANGE_ORDER_SCHEMA.parameters }, normalizedOrder, - order.exchangeAddress, + domain, ); return typedData; }, @@ -60,23 +70,22 @@ export const eip712Utils = { * Creates an ExecuteTransaction EIP712TypedData object for use with signTypedData and * 0x Exchange executeTransaction. * @param ZeroExTransaction the 0x transaction - * @param exchangeAddress The address of the exchange contract * @return A typed data object */ - createZeroExTransactionTypedData: ( - zeroExTransaction: ZeroExTransaction, - exchangeAddress: string, - ): EIP712TypedData => { - assert.isETHAddressHex('exchangeAddress', exchangeAddress); + createZeroExTransactionTypedData: (zeroExTransaction: ZeroExTransaction): EIP712TypedData => { + assert.isETHAddressHex('verifyingContractAddress', zeroExTransaction.verifyingContractAddress); assert.doesConformToSchema('zeroExTransaction', zeroExTransaction, schemas.zeroExTransactionSchema); const normalizedTransaction = _.mapValues(zeroExTransaction, value => { return !_.isString(value) ? value.toString() : value; }); + const domain = { + verifyingContractAddress: zeroExTransaction.verifyingContractAddress, + }; const typedData = eip712Utils.createTypedData( - constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.name, - { ZeroExTransaction: constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.parameters }, + constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name, + { ZeroExTransaction: constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.parameters }, normalizedTransaction, - exchangeAddress, + domain, ); return typedData; }, diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 2150a02e4..ff37d7088 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -3,6 +3,7 @@ export { signatureUtils } from './signature_utils'; export { generatePseudoRandomSalt } from './salt'; export { assetDataUtils } from './asset_data_utils'; export { marketUtils } from './market_utils'; +export { transactionHashUtils } from './transaction_hash'; export { rateUtils } from './rate_utils'; export { sortingUtils } from './sorting_utils'; export { orderParsingUtils } from './parsing_utils'; @@ -50,7 +51,9 @@ export { EIP712Types, EIP712Object, EIP712ObjectValue, + EIP712DomainWithDefaultSchema, ZeroExTransaction, + SignedZeroExTransaction, } from '@0x/types'; export { OrderError, diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts index c8e9be71e..ce7e6d85f 100644 --- a/packages/order-utils/src/order_hash.ts +++ b/packages/order-utils/src/order_hash.ts @@ -4,6 +4,7 @@ import { signTypedDataUtils } from '@0x/utils'; import * as _ from 'lodash'; import { assert } from './assert'; +import { constants } from './constants'; import { eip712Utils } from './eip712_utils'; const INVALID_TAKER_FORMAT = 'instance.takerAddress is not of a type(s) string'; @@ -34,8 +35,9 @@ export const orderHashUtils = { 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'; + const errMsg = `Order taker must be of type string. If you want anyone to be able to fill an order - pass ${ + constants.NULL_ADDRESS + }`; throw new Error(errMsg); } throw error; @@ -51,6 +53,17 @@ export const orderHashUtils = { * @return A Buffer containing the resulting orderHash from hashing the supplied order */ getOrderHashBuffer(order: SignedOrder | Order): Buffer { + 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 ${ + constants.NULL_ADDRESS + }`; + throw new Error(errMsg); + } + throw error; + } const typedData = eip712Utils.createOrderTypedData(order); const orderHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); return orderHashBuff; diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 131144d48..efcc146bf 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -1,4 +1,5 @@ import { ExchangeContract, IValidatorContract, IWalletContract } from '@0x/abi-gen-wrappers'; +import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import * as artifacts from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; import { ECSignature, Order, SignatureType, SignedOrder, ValidatorSignature } from '@0x/types'; @@ -92,7 +93,14 @@ export const signatureUtils = { assert.isWeb3Provider('provider', provider); assert.isHexString('data', data); assert.isETHAddressHex('signerAddress', signerAddress); - const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider); + const web3Wrapper = new Web3Wrapper(provider); + const networkId = await web3Wrapper.getNetworkIdAsync(); + const addresses = getContractAddressesForNetworkOrThrow(networkId); + const exchangeContract = new ExchangeContract( + artifacts.Exchange.compilerOutput.abi, + addresses.exchange, + provider, + ); const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress); return isValid; }, diff --git a/packages/order-utils/src/transaction_hash.ts b/packages/order-utils/src/transaction_hash.ts new file mode 100644 index 000000000..2b2345af7 --- /dev/null +++ b/packages/order-utils/src/transaction_hash.ts @@ -0,0 +1,46 @@ +import { schemas, SchemaValidator } from '@0x/json-schemas'; +import { SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; +import { signTypedDataUtils } from '@0x/utils'; +import * as _ from 'lodash'; + +import { assert } from './assert'; +import { eip712Utils } from './eip712_utils'; + +export const transactionHashUtils = { + /** + * Checks if the supplied hex encoded 0x transaction hash is valid. + * Note: Valid means it has the expected format, not that a transaction with the transactionHash exists. + * Use this method when processing transactionHashes submitted as user input. + * @param transactionHash Hex encoded transactionHash. + * @return Whether the supplied transactionHash has the expected format. + */ + isValidTransactionHash(transactionHash: string): boolean { + // Since this method can be called to check if any arbitrary string conforms to an transactionHash's + // format, we only assert that we were indeed passed a string. + assert.isString('transactionHash', transactionHash); + const schemaValidator = new SchemaValidator(); + const isValid = schemaValidator.validate(transactionHash, schemas.orderHashSchema).valid; + return isValid; + }, + /** + * Computes the transactionHash for a supplied 0x transaction. + * @param transaction An object that conforms to the ZeroExTransaction or SignedZeroExTransaction interface definitions. + * @return Hex encoded string transactionHash from hashing the supplied order. + */ + getTransactionHashHex(transaction: ZeroExTransaction | SignedZeroExTransaction): string { + assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]); + const transactionHashBuff = transactionHashUtils.getTransactionHashBuffer(transaction); + const transactionHashHex = `0x${transactionHashBuff.toString('hex')}`; + return transactionHashHex; + }, + /** + * Computes the transactionHash for a supplied 0x transaction. + * @param transaction An object that conforms to the ZeroExTransaction or SignedZeroExTransaction interface definitions. + * @return A Buffer containing the resulting transactionHash from hashing the supplied 0x transaction. + */ + getTransactionHashBuffer(transaction: ZeroExTransaction | SignedZeroExTransaction): Buffer { + const typedData = eip712Utils.createZeroExTransactionTypedData(transaction); + const transactionHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); + return transactionHashBuff; + }, +}; diff --git a/packages/order-utils/test/eip712_utils_test.ts b/packages/order-utils/test/eip712_utils_test.ts index a54e49958..c97bed144 100644 --- a/packages/order-utils/test/eip712_utils_test.ts +++ b/packages/order-utils/test/eip712_utils_test.ts @@ -12,33 +12,55 @@ const expect = chai.expect; describe('EIP712 Utils', () => { describe('createTypedData', () => { - it('adds in the EIP712DomainSeparator', () => { + it('adds in the EIP712DomainSeparator with default values', () => { const primaryType = 'Test'; const typedData = eip712Utils.createTypedData( primaryType, { Test: [{ name: 'testValue', type: 'uint256' }] }, { testValue: '1' }, - constants.NULL_ADDRESS, + { verifyingContractAddress: constants.NULL_ADDRESS }, ); expect(typedData.domain).to.not.be.undefined(); expect(typedData.types.EIP712Domain).to.not.be.undefined(); const domainObject = typedData.domain; - expect(domainObject.name).to.eq(constants.EIP712_DOMAIN_NAME); + expect(domainObject.name).to.eq(constants.EXCHANGE_DOMAIN_NAME); + expect(domainObject.version).to.eq(constants.EXCHANGE_DOMAIN_VERSION); + expect(domainObject.verifyingContract).to.eq(constants.NULL_ADDRESS); + expect(typedData.primaryType).to.eq(primaryType); + }); + it('adds in the EIP712DomainSeparator without default values', () => { + const primaryType = 'Test'; + const domainName = 'testDomain'; + const domainVersion = 'testVersion'; + const typedData = eip712Utils.createTypedData( + primaryType, + { Test: [{ name: 'testValue', type: 'uint256' }] }, + { testValue: '1' }, + { name: domainName, version: domainVersion, verifyingContractAddress: constants.NULL_ADDRESS }, + ); + expect(typedData.domain).to.not.be.undefined(); + expect(typedData.types.EIP712Domain).to.not.be.undefined(); + const domainObject = typedData.domain; + expect(domainObject.name).to.eq(domainName); + expect(domainObject.version).to.eq(domainVersion); + expect(domainObject.verifyingContract).to.eq(constants.NULL_ADDRESS); expect(typedData.primaryType).to.eq(primaryType); }); }); - describe('createTypedData', () => { + describe('createZeroExTransactionTypedData', () => { it('adds in the EIP712DomainSeparator', () => { - const typedData = eip712Utils.createZeroExTransactionTypedData( - { - salt: new BigNumber('0'), - data: constants.NULL_BYTES, - signerAddress: constants.NULL_ADDRESS, - }, - constants.NULL_ADDRESS, - ); - expect(typedData.primaryType).to.eq(constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.name); + const typedData = eip712Utils.createZeroExTransactionTypedData({ + salt: new BigNumber('0'), + data: constants.NULL_BYTES, + signerAddress: constants.NULL_ADDRESS, + verifyingContractAddress: constants.NULL_ADDRESS, + }); + expect(typedData.primaryType).to.eq(constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name); expect(typedData.types.EIP712Domain).to.not.be.undefined(); + const domainObject = typedData.domain; + expect(domainObject.name).to.eq(constants.EXCHANGE_DOMAIN_NAME); + expect(domainObject.version).to.eq(constants.EXCHANGE_DOMAIN_VERSION); + expect(domainObject.verifyingContract).to.eq(constants.NULL_ADDRESS); }); }); }); diff --git a/packages/order-utils/test/order_hash_test.ts b/packages/order-utils/test/order_hash_test.ts index 30fb15a37..514fc2709 100644 --- a/packages/order-utils/test/order_hash_test.ts +++ b/packages/order-utils/test/order_hash_test.ts @@ -54,8 +54,9 @@ describe('Order hashing', () => { ...order, takerAddress: (null as any) as string, }; - const expectedErrorMessage = - 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS'; + const expectedErrorMessage = `Order taker must be of type string. If you want anyone to be able to fill an order - pass ${ + constants.NULL_ADDRESS + }`; expect(() => orderHashUtils.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage); }); }); diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts index 937382056..44aa729b3 100644 --- a/packages/order-utils/test/signature_utils_test.ts +++ b/packages/order-utils/test/signature_utils_test.ts @@ -99,6 +99,17 @@ describe('Signature utils', () => { ); expect(isValidSignatureLocal).to.be.true(); }); + + it('should return false if entry not found in `preSigned` mapping', async () => { + const preSignedSignature = '0x06'; + const isValidPreSignature = await signatureUtils.isValidSignatureAsync( + provider, + dataHex, + preSignedSignature, + address, + ); + expect(isValidPreSignature).to.be.false(); + }); }); describe('#isValidECSignature', () => { const signature = { diff --git a/packages/order-utils/test/transaction_hash_test.ts b/packages/order-utils/test/transaction_hash_test.ts new file mode 100644 index 000000000..c7ca33a64 --- /dev/null +++ b/packages/order-utils/test/transaction_hash_test.ts @@ -0,0 +1,56 @@ +import { ZeroExTransaction } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { transactionHashUtils } from '../src'; + +import { constants } from '../src/constants'; + +import { chaiSetup } from './utils/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('0x transaction hashing', () => { + describe('#getTransactionHashHex', () => { + const expectedTransactionHash = '0x82c9bb2dcac4f868ec7a15c20ff6175cfc384c20ae6a872aa0342a840f108c2b'; + const fakeVerifyingContractAddress = '0x5e72914535f202659083db3a02c984188fa26e9f'; + const transaction: ZeroExTransaction = { + verifyingContractAddress: fakeVerifyingContractAddress, + signerAddress: constants.NULL_ADDRESS, + salt: new BigNumber(0), + data: constants.NULL_BYTES, + }; + it('calculates the transaction hash', async () => { + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(transactionHash).to.be.equal(expectedTransactionHash); + }); + it('calculates the transaction hash if amounts are strings', async () => { + // It's common for developers using javascript to provide the amounts + // as strings. Since we eventually toString() the BigNumber + // before encoding we should result in the same orderHash in this scenario + // tslint:disable-next-line:no-unnecessary-type-assertion + const transactionHash = transactionHashUtils.getTransactionHashHex({ + ...transaction, + salt: '0', + } as any); + expect(transactionHash).to.be.equal(expectedTransactionHash); + }); + }); + describe('#isValidTransactionHash', () => { + it('returns false if the value is not a hex string', () => { + const isValid = transactionHashUtils.isValidTransactionHash('not a hex'); + expect(isValid).to.be.false(); + }); + it('returns false if the length is wrong', () => { + const isValid = transactionHashUtils.isValidTransactionHash('0xdeadbeef'); + expect(isValid).to.be.false(); + }); + it('returns true if order hash is correct', () => { + const orderHashLength = 65; + const isValid = transactionHashUtils.isValidTransactionHash(`0x${Array(orderHashLength).join('0')}`); + expect(isValid).to.be.true(); + }); + }); +}); |