aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils')
-rw-r--r--packages/order-utils/CHANGELOG.json56
-rw-r--r--packages/order-utils/CHANGELOG.md20
-rw-r--r--packages/order-utils/package.json26
-rw-r--r--packages/order-utils/src/asset_data_utils.ts293
-rw-r--r--packages/order-utils/src/constants.ts66
-rw-r--r--packages/order-utils/src/exchange_transfer_simulator.ts64
-rw-r--r--packages/order-utils/src/index.ts5
-rw-r--r--packages/order-utils/src/order_state_utils.ts56
-rw-r--r--packages/order-utils/src/signature_utils.ts2
-rw-r--r--packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts2
-rw-r--r--packages/order-utils/test/asset_data_utils_test.ts116
-rw-r--r--packages/order-utils/test/order_hash_test.ts2
-rw-r--r--packages/order-utils/test/utils/test_order_factory.ts4
13 files changed, 581 insertions, 131 deletions
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json
index 55e7defda..292f7a57b 100644
--- a/packages/order-utils/CHANGELOG.json
+++ b/packages/order-utils/CHANGELOG.json
@@ -1,5 +1,61 @@
[
{
+ "version": "3.1.0",
+ "changes": [
+ {
+ "note":
+ "Use new ABI encoder, add encoding/decoding logic for MultiAsset assetData, and add information to return values in orderStateUtils",
+ "pr": 1363
+ }
+ ]
+ },
+ {
+ "version": "3.0.7",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1544739608
+ },
+ {
+ "version": "3.0.6",
+ "changes": [
+ {
+ "note": "Fix bug in wallet signature type verification",
+ "pr": 1414
+ }
+ ],
+ "timestamp": 1544570656
+ },
+ {
+ "timestamp": 1544482891,
+ "version": "3.0.5",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
+ "timestamp": 1543401373,
+ "version": "3.0.4",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
+ "timestamp": 1542821676,
+ "version": "3.0.3",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542208198,
"version": "3.0.2",
"changes": [
diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md
index edf1569a7..bc8b48767 100644
--- a/packages/order-utils/CHANGELOG.md
+++ b/packages/order-utils/CHANGELOG.md
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.7 - _December 13, 2018_
+
+ * Dependencies updated
+
+## v3.0.6 - _December 11, 2018_
+
+ * Fix bug in wallet signature type verification (#1414)
+
+## v3.0.5 - _December 10, 2018_
+
+ * Dependencies updated
+
+## v3.0.4 - _November 28, 2018_
+
+ * Dependencies updated
+
+## v3.0.3 - _November 21, 2018_
+
+ * Dependencies updated
+
## v3.0.2 - _November 14, 2018_
* Dependencies updated
diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json
index fe5ea70b1..400c9b66f 100644
--- a/packages/order-utils/package.json
+++ b/packages/order-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/order-utils",
- "version": "3.0.2",
+ "version": "3.0.7",
"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.17",
- "@0x/tslint-config": "^1.0.10",
+ "@0x/dev-utils": "^1.0.21",
+ "@0x/tslint-config": "^2.0.0",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"chai": "^4.0.1",
@@ -53,18 +53,18 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.0.5",
- "@0x/assert": "^1.0.17",
- "@0x/base-contract": "^3.0.6",
- "@0x/contract-artifacts": "^1.1.0",
- "@0x/json-schemas": "^2.1.1",
- "@0x/types": "^1.2.1",
- "@0x/typescript-typings": "^3.0.4",
- "@0x/utils": "^2.0.5",
- "@0x/web3-wrapper": "^3.1.4",
+ "@0x/abi-gen-wrappers": "^2.0.2",
+ "@0x/assert": "^1.0.20",
+ "@0x/base-contract": "^3.0.10",
+ "@0x/contract-artifacts": "^1.1.2",
+ "@0x/json-schemas": "^2.1.4",
+ "@0x/types": "^1.4.1",
+ "@0x/typescript-typings": "^3.0.6",
+ "@0x/utils": "^2.0.8",
+ "@0x/web3-wrapper": "^3.2.1",
"@types/node": "*",
"bn.js": "^4.11.8",
- "ethereum-types": "^1.1.2",
+ "ethereum-types": "^1.1.4",
"ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1",
"ethers": "~4.0.4",
diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts
index 9bbef3a23..f314891e2 100644
--- a/packages/order-utils/src/asset_data_utils.ts
+++ b/packages/order-utils/src/asset_data_utils.ts
@@ -1,10 +1,19 @@
-import { AssetData, AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import ethAbi = require('ethereumjs-abi');
-import ethUtil = require('ethereumjs-util');
+import {
+ AssetProxyId,
+ ERC20AssetData,
+ ERC721AssetData,
+ MultiAssetData,
+ MultiAssetDataWithRecursiveDecoding,
+ SingleAssetData,
+} from '@0x/types';
+import { AbiEncoder, BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
import { constants } from './constants';
+const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: true };
+const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
+
export const assetDataUtils = {
/**
* Encodes an ERC20 token address into a hex encoded assetData string, usable in the makerAssetData or
@@ -13,7 +22,10 @@ export const assetDataUtils = {
* @return The hex encoded assetData string
*/
encodeERC20AssetData(tokenAddress: string): string {
- return ethUtil.bufferToHex(ethAbi.simpleEncode('ERC20Token(address)', tokenAddress));
+ const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
+ const args = [tokenAddress];
+ const assetData = abiEncoder.encode(args, encodingRules);
+ return assetData;
},
/**
* Decodes an ERC20 assetData hex string into it's corresponding ERC20 tokenAddress & assetProxyId
@@ -21,26 +33,14 @@ export const assetDataUtils = {
* @return An object containing the decoded tokenAddress & assetProxyId
*/
decodeERC20AssetData(assetData: string): ERC20AssetData {
- const data = ethUtil.toBuffer(assetData);
- if (data.byteLength < constants.ERC20_ASSET_DATA_BYTE_LENGTH) {
- throw new Error(
- `Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least ${
- constants.ERC20_ASSET_DATA_BYTE_LENGTH
- }. Got ${data.byteLength}`,
- );
- }
- const assetProxyId = ethUtil.bufferToHex(data.slice(0, constants.SELECTOR_LENGTH));
- if (assetProxyId !== AssetProxyId.ERC20) {
- throw new Error(
- `Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be ERC20 (${
- AssetProxyId.ERC20
- }), but got ${assetProxyId}`,
- );
- }
- const [tokenAddress] = ethAbi.rawDecode(['address'], data.slice(constants.SELECTOR_LENGTH));
+ assetDataUtils.assertIsERC20AssetData(assetData);
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
+ const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
return {
assetProxyId,
- tokenAddress: ethUtil.addHexPrefix(tokenAddress),
+ // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
+ tokenAddress: (decodedAssetData as any).tokenContract,
};
},
/**
@@ -51,14 +51,10 @@ export const assetDataUtils = {
* @return The hex encoded assetData string
*/
encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
- // TODO: Pass `tokendId` as a BigNumber.
- return ethUtil.bufferToHex(
- ethAbi.simpleEncode(
- 'ERC721Token(address,uint256)',
- tokenAddress,
- `0x${tokenId.toString(constants.BASE_16)}`,
- ),
- );
+ const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
+ const args = [tokenAddress, tokenId];
+ const assetData = abiEncoder.encode(args, encodingRules);
+ return assetData;
},
/**
* Decodes an ERC721 assetData hex string into it's corresponding ERC721 tokenAddress, tokenId & assetProxyId
@@ -66,27 +62,99 @@ export const assetDataUtils = {
* @return An object containing the decoded tokenAddress, tokenId & assetProxyId
*/
decodeERC721AssetData(assetData: string): ERC721AssetData {
- const data = ethUtil.toBuffer(assetData);
- if (data.byteLength < constants.ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH) {
+ assetDataUtils.assertIsERC721AssetData(assetData);
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
+ const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
+ return {
+ assetProxyId,
+ // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
+ tokenAddress: (decodedAssetData as any).tokenContract,
+ tokenId: (decodedAssetData as any).tokenId,
+ };
+ },
+ /**
+ * Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or
+ * takerAssetData fields in a 0x order.
+ * @param amounts Amounts of each asset that correspond to a single unit within an order.
+ * @param nestedAssetData assetData strings that correspond to a valid assetProxyId.
+ * @return The hex encoded assetData string
+ */
+ encodeMultiAssetData(amounts: BigNumber[], nestedAssetData: string[]): string {
+ if (amounts.length !== nestedAssetData.length) {
throw new Error(
- `Could not decode ERC721 Asset Data. Expected length of encoded data to be at least ${
- constants.ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH
- }. Got ${data.byteLength}`,
+ `Invalid MultiAsset arguments. Expected length of 'amounts' (${
+ amounts.length
+ }) to equal length of 'nestedAssetData' (${nestedAssetData.length})`,
);
}
- const assetProxyId = ethUtil.bufferToHex(data.slice(0, constants.SELECTOR_LENGTH));
- if (assetProxyId !== AssetProxyId.ERC721) {
+ _.forEach(nestedAssetData, assetDataElement => assetDataUtils.validateAssetDataOrThrow(assetDataElement));
+ const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
+ const args = [amounts, nestedAssetData];
+ const assetData = abiEncoder.encode(args, encodingRules);
+ return assetData;
+ },
+ /**
+ * Decodes a MultiAsset assetData hex string into it's corresponding amounts and nestedAssetData
+ * @param assetData Hex encoded assetData string to decode
+ * @return An object containing the decoded amounts and nestedAssetData
+ */
+ decodeMultiAssetData(assetData: string): MultiAssetData {
+ assetDataUtils.assertIsMultiAssetData(assetData);
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
+ const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
+ // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
+ const amounts = (decodedAssetData as any).amounts;
+ const nestedAssetData = (decodedAssetData as any).nestedAssetData;
+ if (amounts.length !== nestedAssetData.length) {
throw new Error(
- `Could not decode ERC721 Asset Data. Expected Asset Proxy Id to be ERC721 (${
- AssetProxyId.ERC721
- }), but got ${assetProxyId}`,
+ `Invalid MultiAsset assetData. Expected length of 'amounts' (${
+ amounts.length
+ }) to equal length of 'nestedAssetData' (${nestedAssetData.length})`,
);
}
- const [tokenAddress, tokenId] = ethAbi.rawDecode(['address', 'uint256'], data.slice(constants.SELECTOR_LENGTH));
return {
assetProxyId,
- tokenAddress: ethUtil.addHexPrefix(tokenAddress),
- tokenId: new BigNumber(tokenId.toString()),
+ amounts,
+ nestedAssetData,
+ };
+ },
+ /**
+ * Decodes a MultiAsset assetData hex string into it's corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened)
+ * @param assetData Hex encoded assetData string to decode
+ * @return An object containing the decoded amounts and nestedAssetData
+ */
+ decodeMultiAssetDataRecursively(assetData: string): MultiAssetDataWithRecursiveDecoding {
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ const amounts: any[] = [];
+ const decodedNestedAssetData = _.map(
+ decodedAssetData.nestedAssetData as string[],
+ (nestedAssetDataElement, index) => {
+ const decodedNestedAssetDataElement = assetDataUtils.decodeAssetDataOrThrow(nestedAssetDataElement);
+ if (decodedNestedAssetDataElement.assetProxyId === AssetProxyId.MultiAsset) {
+ const recursivelyDecodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(
+ nestedAssetDataElement,
+ );
+ amounts.push(
+ _.map(recursivelyDecodedAssetData.amounts, amountElement =>
+ amountElement.times(decodedAssetData.amounts[index]),
+ ),
+ );
+ return recursivelyDecodedAssetData.nestedAssetData;
+ } else {
+ amounts.push(decodedAssetData.amounts[index]);
+ return decodedNestedAssetDataElement as SingleAssetData;
+ }
+ },
+ );
+ const flattenedAmounts = _.flattenDeep(amounts);
+ const flattenedDecodedNestedAssetData = _.flattenDeep(decodedNestedAssetData);
+ return {
+ assetProxyId: decodedAssetData.assetProxyId,
+ amounts: flattenedAmounts,
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ nestedAssetData: flattenedDecodedNestedAssetData as SingleAssetData[],
};
},
/**
@@ -95,24 +163,133 @@ export const assetDataUtils = {
* @return The assetProxyId
*/
decodeAssetProxyId(assetData: string): AssetProxyId {
- const encodedAssetData = ethUtil.toBuffer(assetData);
- if (encodedAssetData.byteLength < constants.SELECTOR_LENGTH) {
+ if (assetData.length < constants.SELECTOR_CHAR_LENGTH_WITH_PREFIX) {
throw new Error(
- `Could not decode assetData. Expected length of encoded data to be at least 4. Got ${
- encodedAssetData.byteLength
+ `Could not decode assetData. Expected length of encoded data to be at least 10. Got ${
+ assetData.length
}`,
);
}
- const encodedAssetProxyId = encodedAssetData.slice(0, constants.SELECTOR_LENGTH);
- const assetProxyId = decodeAssetProxyId(encodedAssetProxyId);
+ const assetProxyId = assetData.slice(0, constants.SELECTOR_CHAR_LENGTH_WITH_PREFIX);
+ if (
+ assetProxyId !== AssetProxyId.ERC20 &&
+ assetProxyId !== AssetProxyId.ERC721 &&
+ assetProxyId !== AssetProxyId.MultiAsset
+ ) {
+ throw new Error(`Invalid assetProxyId: ${assetProxyId}`);
+ }
return assetProxyId;
},
/**
+ * Checks if the decoded asset data is valid ERC20 data
+ * @param decodedAssetData The decoded asset data to check
+ */
+ isERC20AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC20AssetData {
+ return decodedAssetData.assetProxyId === AssetProxyId.ERC20;
+ },
+ /**
+ * Checks if the decoded asset data is valid ERC721 data
+ * @param decodedAssetData The decoded asset data to check
+ */
+ isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC721AssetData {
+ return decodedAssetData.assetProxyId === AssetProxyId.ERC721;
+ },
+ /**
+ * Checks if the decoded asset data is valid MultiAsset data
+ * @param decodedAssetData The decoded asset data to check
+ */
+ isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData {
+ return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset;
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the ERC20Proxy.
+ * @param assetData Hex encoded assetData string
+ */
+ assertIsERC20AssetData(assetData: string): void {
+ if (assetData.length < constants.ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
+ throw new Error(
+ `Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least ${
+ constants.ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
+ }. Got ${assetData.length}`,
+ );
+ }
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ if (assetProxyId !== AssetProxyId.ERC20) {
+ throw new Error(
+ `Could not decode ERC20 assetData. Expected assetProxyId to be ERC20 (${
+ AssetProxyId.ERC20
+ }), but got ${assetProxyId}`,
+ );
+ }
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the ERC721Proxy.
+ * @param assetData Hex encoded assetData string
+ */
+ assertIsERC721AssetData(assetData: string): void {
+ if (assetData.length < constants.ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
+ throw new Error(
+ `Could not decode ERC721 assetData. Expected length of encoded data to be at least ${
+ constants.ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
+ }. Got ${assetData.length}`,
+ );
+ }
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ if (assetProxyId !== AssetProxyId.ERC721) {
+ throw new Error(
+ `Could not decode ERC721 assetData. Expected assetProxyId to be ERC721 (${
+ AssetProxyId.ERC721
+ }), but got ${assetProxyId}`,
+ );
+ }
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the MultiAssetProxy.
+ * @param assetData Hex encoded assetData string
+ */
+ assertIsMultiAssetData(assetData: string): void {
+ if (assetData.length < constants.MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
+ throw new Error(
+ `Could not decode MultiAsset assetData. Expected length of encoded data to be at least ${
+ constants.MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
+ }. Got ${assetData.length}`,
+ );
+ }
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ if (assetProxyId !== AssetProxyId.MultiAsset) {
+ throw new Error(
+ `Could not decode MultiAsset assetData. Expected assetProxyId to be MultiAsset (${
+ AssetProxyId.MultiAsset
+ }), but got ${assetProxyId}`,
+ );
+ }
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the corresponding AssetProxy.
+ * @param assetData Hex encoded assetData string
+ */
+ validateAssetDataOrThrow(assetData: string): void {
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ assetDataUtils.assertIsERC20AssetData(assetData);
+ break;
+ case AssetProxyId.ERC721:
+ assetDataUtils.assertIsERC721AssetData(assetData);
+ break;
+ case AssetProxyId.MultiAsset:
+ assetDataUtils.assertIsMultiAssetData(assetData);
+ break;
+ default:
+ throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
+ }
+ },
+ /**
* Decode any assetData into it's corresponding assetData object
* @param assetData Hex encoded assetData string to decode
* @return Either a ERC20 or ERC721 assetData object
*/
- decodeAssetDataOrThrow(assetData: string): AssetData {
+ decodeAssetDataOrThrow(assetData: string): SingleAssetData | MultiAssetData {
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
switch (assetProxyId) {
case AssetProxyId.ERC20:
@@ -121,19 +298,11 @@ export const assetDataUtils = {
case AssetProxyId.ERC721:
const erc721AssetData = assetDataUtils.decodeERC721AssetData(assetData);
return erc721AssetData;
+ case AssetProxyId.MultiAsset:
+ const multiAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ return multiAssetData;
default:
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
}
},
};
-
-function decodeAssetProxyId(encodedAssetProxyId: Buffer): AssetProxyId {
- const hexString = ethUtil.bufferToHex(encodedAssetProxyId);
- if (hexString === AssetProxyId.ERC20) {
- return AssetProxyId.ERC20;
- }
- if (hexString === AssetProxyId.ERC721) {
- return AssetProxyId.ERC721;
- }
- throw new Error(`Invalid ProxyId: ${hexString}`);
-}
diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts
index 10029dcc3..a9a687719 100644
--- a/packages/order-utils/src/constants.ts
+++ b/packages/order-utils/src/constants.ts
@@ -1,16 +1,71 @@
import { BigNumber } from '@0x/utils';
+import { MethodAbi } from 'ethereum-types';
+
+const ERC20_METHOD_ABI: MethodAbi = {
+ constant: false,
+ inputs: [
+ {
+ name: 'tokenContract',
+ type: 'address',
+ },
+ ],
+ name: 'ERC20Token',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function',
+};
+
+const ERC721_METHOD_ABI: MethodAbi = {
+ constant: false,
+ inputs: [
+ {
+ name: 'tokenContract',
+ type: 'address',
+ },
+ {
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'ERC721Token',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function',
+};
+
+const MULTI_ASSET_METHOD_ABI: MethodAbi = {
+ constant: false,
+ inputs: [
+ {
+ name: 'amounts',
+ type: 'uint256[]',
+ },
+ {
+ name: 'nestedAssetData',
+ type: 'bytes[]',
+ },
+ ],
+ name: 'MultiAsset',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function',
+};
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
NULL_BYTES: '0x',
+ NULL_ERC20_ASSET_DATA: '0xf47261b00000000000000000000000000000000000000000000000000000000000000000',
// tslint:disable-next-line:custom-no-magic-numbers
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
TESTRPC_NETWORK_ID: 50,
ADDRESS_LENGTH: 20,
- ERC20_ASSET_DATA_BYTE_LENGTH: 36,
- ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH: 53,
- SELECTOR_LENGTH: 4,
- BASE_16: 16,
+ ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 74,
+ ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 136,
+ MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 266,
+ 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',
@@ -48,4 +103,7 @@ export const constants = {
{ name: 'data', type: 'bytes' },
],
},
+ ERC20_METHOD_ABI,
+ ERC721_METHOD_ABI,
+ MULTI_ASSET_METHOD_ABI,
};
diff --git a/packages/order-utils/src/exchange_transfer_simulator.ts b/packages/order-utils/src/exchange_transfer_simulator.ts
index 7a38b35df..06621fd9e 100644
--- a/packages/order-utils/src/exchange_transfer_simulator.ts
+++ b/packages/order-utils/src/exchange_transfer_simulator.ts
@@ -1,7 +1,8 @@
-import { ExchangeContractErrs } from '@0x/types';
+import { AssetProxyId, ExchangeContractErrs } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store';
+import { assetDataUtils } from './asset_data_utils';
import { constants } from './constants';
import { TradeSide, TransferType } from './types';
@@ -74,24 +75,51 @@ export class ExchangeTransferSimulator {
tradeSide: TradeSide,
transferType: TransferType,
): Promise<void> {
- // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
- // allowances for the taker. We do however, want to increase the balance of the maker since the maker
- // might be relying on those funds to fill subsequent orders or pay the order's fees.
- if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
- await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
- return;
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ case AssetProxyId.ERC721:
+ // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
+ // allowances for the taker. We do however, want to increase the balance of the maker since the maker
+ // might be relying on those funds to fill subsequent orders or pay the order's fees.
+ if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
+ await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
+ return;
+ }
+ const balance = await this._store.getBalanceAsync(assetData, from);
+ const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
+ if (proxyAllowance.lessThan(amountInBaseUnits)) {
+ ExchangeTransferSimulator._throwValidationError(
+ FailureReason.ProxyAllowance,
+ tradeSide,
+ transferType,
+ );
+ }
+ if (balance.lessThan(amountInBaseUnits)) {
+ ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
+ }
+ await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
+ await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
+ await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
+ break;
+ case AssetProxyId.MultiAsset:
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
+ const amountsElement = decodedAssetData.amounts[index];
+ const totalAmount = amountInBaseUnits.times(amountsElement);
+ await this.transferFromAsync(
+ nestedAssetDataElement,
+ from,
+ to,
+ totalAmount,
+ tradeSide,
+ transferType,
+ );
+ }
+ break;
+ default:
+ break;
}
- const balance = await this._store.getBalanceAsync(assetData, from);
- const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
- if (proxyAllowance.lessThan(amountInBaseUnits)) {
- ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
- }
- if (balance.lessThan(amountInBaseUnits)) {
- ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
- }
- await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
- await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
- await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
}
private async _decreaseProxyAllowanceAsync(
assetData: string,
diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts
index e70d43efb..2150a02e4 100644
--- a/packages/order-utils/src/index.ts
+++ b/packages/order-utils/src/index.ts
@@ -34,11 +34,14 @@ export {
OrderRelevantState,
OrderState,
ECSignature,
- AssetData,
+ SingleAssetData,
ERC20AssetData,
ERC721AssetData,
+ MultiAssetData,
+ MultiAssetDataWithRecursiveDecoding,
AssetProxyId,
SignatureType,
+ ObjectMap,
OrderStateValid,
OrderStateInvalid,
ExchangeContractErrs,
diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts
index fe0d6c773..389419587 100644
--- a/packages/order-utils/src/order_state_utils.ts
+++ b/packages/order-utils/src/order_state_utils.ts
@@ -1,5 +1,6 @@
import {
ExchangeContractErrs,
+ ObjectMap,
OrderRelevantState,
OrderState,
OrderStateInvalid,
@@ -7,9 +8,11 @@ import {
SignedOrder,
} from '@0x/types';
import { BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
+import { assetDataUtils } from './asset_data_utils';
import { orderHashUtils } from './order_hash';
import { OrderValidationUtils } from './order_validation_utils';
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
@@ -18,7 +21,9 @@ import { utils } from './utils';
interface SidedOrderRelevantState {
isMakerSide: boolean;
traderBalance: BigNumber;
+ traderIndividualBalances: ObjectMap<BigNumber>;
traderProxyAllowance: BigNumber;
+ traderIndividualProxyAllowances: ObjectMap<BigNumber>;
traderFeeBalance: BigNumber;
traderFeeProxyAllowance: BigNumber;
filledTakerAssetAmount: BigNumber;
@@ -121,7 +126,9 @@ export class OrderStateUtils {
const sidedOrderRelevantState = {
isMakerSide: true,
traderBalance: orderRelevantState.makerBalance,
+ traderIndividualBalances: orderRelevantState.makerIndividualBalances,
traderProxyAllowance: orderRelevantState.makerProxyAllowance,
+ traderIndividualProxyAllowances: orderRelevantState.makerIndividualProxyAllowances,
traderFeeBalance: orderRelevantState.makerFeeBalance,
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
@@ -165,7 +172,9 @@ export class OrderStateUtils {
const orderRelevantState = {
makerBalance: sidedOrderRelevantState.traderBalance,
+ makerIndividualBalances: sidedOrderRelevantState.traderIndividualBalances,
makerProxyAllowance: sidedOrderRelevantState.traderProxyAllowance,
+ makerIndividualProxyAllowances: sidedOrderRelevantState.traderIndividualProxyAllowances,
makerFeeBalance: sidedOrderRelevantState.traderFeeBalance,
makerFeeProxyAllowance: sidedOrderRelevantState.traderFeeProxyAllowance,
filledTakerAssetAmount: sidedOrderRelevantState.filledTakerAssetAmount,
@@ -236,10 +245,12 @@ export class OrderStateUtils {
const isAssetZRX = assetData === zrxAssetData;
const traderBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
+ const traderIndividualBalances = await this._getAssetBalancesAsync(assetData, traderAddress);
const traderProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
assetData,
traderAddress,
);
+ const traderIndividualProxyAllowances = await this._getAssetProxyAllowancesAsync(assetData, traderAddress);
const traderFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
zrxAssetData,
traderAddress,
@@ -278,7 +289,9 @@ export class OrderStateUtils {
const sidedOrderRelevantState = {
isMakerSide,
traderBalance,
+ traderIndividualBalances,
traderProxyAllowance,
+ traderIndividualProxyAllowances,
traderFeeBalance,
traderFeeProxyAllowance,
filledTakerAssetAmount,
@@ -287,4 +300,47 @@ export class OrderStateUtils {
};
return sidedOrderRelevantState;
}
+ private async _getAssetBalancesAsync(
+ assetData: string,
+ traderAddress: string,
+ initialBalances: ObjectMap<BigNumber> = {},
+ ): Promise<ObjectMap<BigNumber>> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ let balances: ObjectMap<BigNumber> = { ...initialBalances };
+ if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
+ const tokenAddress = decodedAssetData.tokenAddress;
+ balances[tokenAddress] = _.isUndefined(initialBalances[tokenAddress])
+ ? balance
+ : balances[tokenAddress].add(balance);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ for (const assetDataElement of decodedAssetData.nestedAssetData) {
+ balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances);
+ }
+ }
+ return balances;
+ }
+ private async _getAssetProxyAllowancesAsync(
+ assetData: string,
+ traderAddress: string,
+ initialAllowances: ObjectMap<BigNumber> = {},
+ ): Promise<ObjectMap<BigNumber>> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ let allowances: ObjectMap<BigNumber> = { ...initialAllowances };
+ if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
+ assetData,
+ traderAddress,
+ );
+ const tokenAddress = decodedAssetData.tokenAddress;
+ allowances[tokenAddress] = _.isUndefined(initialAllowances[tokenAddress])
+ ? allowance
+ : allowances[tokenAddress].add(allowance);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ for (const assetDataElement of decodedAssetData.nestedAssetData) {
+ allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances);
+ }
+ }
+ return allowances;
+ }
}
diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts
index 96d90e21a..131144d48 100644
--- a/packages/order-utils/src/signature_utils.ts
+++ b/packages/order-utils/src/signature_utils.ts
@@ -115,7 +115,7 @@ export const signatureUtils = {
assert.isHexString('signature', signature);
assert.isETHAddressHex('signerAddress', signerAddress);
// tslint:disable-next-line:custom-no-magic-numbers
- const signatureWithoutType = signature.slice(-2);
+ const signatureWithoutType = signature.slice(0, -2);
const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider);
const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType);
return isValid;
diff --git a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts b/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
index f42a76d0c..ae3e36238 100644
--- a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
+++ b/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
@@ -119,7 +119,7 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
public deleteAllERC721ProxyAllowance(tokenAddress: string, userAddress: string): void {
for (const assetData in this._proxyAllowance) {
if (this._proxyAllowance.hasOwnProperty(assetData)) {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ const decodedAssetData = assetDataUtils.decodeERC721AssetData(assetData);
if (
decodedAssetData.assetProxyId === AssetProxyId.ERC721 &&
decodedAssetData.tokenAddress === tokenAddress &&
diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts
index f175b7a38..c498c5a00 100644
--- a/packages/order-utils/test/asset_data_utils_test.ts
+++ b/packages/order-utils/test/asset_data_utils_test.ts
@@ -1,6 +1,6 @@
import * as chai from 'chai';
-import { ERC20AssetData, ERC721AssetData } from '@0x/types';
+import { AssetProxyId, ERC721AssetData } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { assetDataUtils } from '../src/asset_data_utils';
@@ -10,41 +10,101 @@ import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
-const KNOWN_ENCODINGS = [
- {
- address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
- assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
- },
- {
- address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
- tokenId: new BigNumber(1),
- assetData:
- '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
- },
-];
-
-const ERC20_ASSET_PROXY_ID = '0xf47261b0';
-const ERC721_ASSET_PROXY_ID = '0x02571792';
+const KNOWN_ERC20_ENCODING = {
+ address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
+ assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
+};
+const KNOWN_ERC721_ENCODING = {
+ address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
+ tokenId: new BigNumber(1),
+ assetData:
+ '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
+};
+const KNOWN_MULTI_ASSET_ENCODING = {
+ amounts: [new BigNumber(1), new BigNumber(1)],
+ nestedAssetData: [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData],
+ assetData:
+ '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
+};
describe('assetDataUtils', () => {
it('should encode ERC20', () => {
- const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ENCODINGS[0].address);
- expect(assetData).to.equal(KNOWN_ENCODINGS[0].assetData);
+ const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address);
+ expect(assetData).to.equal(KNOWN_ERC20_ENCODING.assetData);
});
it('should decode ERC20', () => {
- const assetData: ERC20AssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ENCODINGS[0].assetData);
- expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[0].address);
- expect(assetData.assetProxyId).to.equal(ERC20_ASSET_PROXY_ID);
+ const decodedAssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData);
+ expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
});
it('should encode ERC721', () => {
- const assetData = assetDataUtils.encodeERC721AssetData(KNOWN_ENCODINGS[1].address, KNOWN_ENCODINGS[1]
- .tokenId as BigNumber);
- expect(assetData).to.equal(KNOWN_ENCODINGS[1].assetData);
+ const assetData = assetDataUtils.encodeERC721AssetData(
+ KNOWN_ERC721_ENCODING.address,
+ KNOWN_ERC721_ENCODING.tokenId,
+ );
+ expect(assetData).to.equal(KNOWN_ERC721_ENCODING.assetData);
});
it('should decode ERC721', () => {
- const assetData: ERC721AssetData = assetDataUtils.decodeERC721AssetData(KNOWN_ENCODINGS[1].assetData);
- expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[1].address);
- expect(assetData.assetProxyId).to.equal(ERC721_ASSET_PROXY_ID);
- expect(assetData.tokenId).to.be.bignumber.equal(KNOWN_ENCODINGS[1].tokenId);
+ const decodedAssetData = assetDataUtils.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData);
+ expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
+ });
+ it('should encode ERC20 and ERC721 multiAssetData', () => {
+ const assetData = assetDataUtils.encodeMultiAssetData(
+ KNOWN_MULTI_ASSET_ENCODING.amounts,
+ KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
+ );
+ expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
+ });
+ it('should decode ERC20 and ERC721 multiAssetData', () => {
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
+ expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
+ expect(decodedAssetData.nestedAssetData).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.nestedAssetData);
+ });
+ it('should recursively decode ERC20 and ERC721 multiAssetData', () => {
+ const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(KNOWN_MULTI_ASSET_ENCODING.assetData);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
+ expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
+ const decodedErc20AssetData = decodedAssetData.nestedAssetData[0];
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const decodedErc721AssetData = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
+ expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
+ expect(decodedErc721AssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedErc721AssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedErc721AssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
+ });
+ it('should recursively decode nested assetData within multiAssetData', () => {
+ const amounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2)];
+ const nestedAssetData = [
+ KNOWN_ERC20_ENCODING.assetData,
+ KNOWN_ERC721_ENCODING.assetData,
+ KNOWN_MULTI_ASSET_ENCODING.assetData,
+ ];
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
+ const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(assetData);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
+ const expectedAmounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2), new BigNumber(2)];
+ expect(decodedAssetData.amounts).to.deep.equal(expectedAmounts);
+ const expectedLength = 4;
+ expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedLength);
+ const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[0];
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
+ const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[2];
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const decodedErc721AssetData2 = decodedAssetData.nestedAssetData[3] as ERC721AssetData;
+ expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20);
+ expect(decodedErc721AssetData1.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedErc721AssetData1.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedErc721AssetData1.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
+ expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20);
+ expect(decodedErc721AssetData2.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedErc721AssetData2.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedErc721AssetData2.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
});
});
diff --git a/packages/order-utils/test/order_hash_test.ts b/packages/order-utils/test/order_hash_test.ts
index a85d4c81a..30fb15a37 100644
--- a/packages/order-utils/test/order_hash_test.ts
+++ b/packages/order-utils/test/order_hash_test.ts
@@ -70,7 +70,7 @@ describe('Order hashing', () => {
});
it('returns true if order hash is correct', () => {
const orderHashLength = 65;
- const isValid = orderHashUtils.isValidOrderHash('0x' + Array(orderHashLength).join('0'));
+ const isValid = orderHashUtils.isValidOrderHash(`0x${Array(orderHashLength).join('0')}`);
expect(isValid).to.be.true();
});
});
diff --git a/packages/order-utils/test/utils/test_order_factory.ts b/packages/order-utils/test/utils/test_order_factory.ts
index 145332674..4efe0b38e 100644
--- a/packages/order-utils/test/utils/test_order_factory.ts
+++ b/packages/order-utils/test/utils/test_order_factory.ts
@@ -7,9 +7,9 @@ import { orderFactory } from '../../src/order_factory';
const BASE_TEST_ORDER: Order = orderFactory.createOrder(
constants.NULL_ADDRESS,
constants.ZERO_AMOUNT,
- constants.NULL_ADDRESS,
+ constants.NULL_ERC20_ASSET_DATA,
constants.ZERO_AMOUNT,
- constants.NULL_ADDRESS,
+ constants.NULL_ERC20_ASSET_DATA,
constants.NULL_ADDRESS,
);
const BASE_TEST_SIGNED_ORDER: SignedOrder = {