aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/0x.js/package.json2
-rw-r--r--packages/abi-gen-wrappers/package.json2
-rw-r--r--packages/abi-gen/package.json2
-rw-r--r--packages/assert/package.json2
-rw-r--r--packages/asset-buyer/package.json2
-rw-r--r--packages/base-contract/package.json2
-rw-r--r--packages/connect/package.json2
-rw-r--r--packages/contract-wrappers/CHANGELOG.json9
-rw-r--r--packages/contract-wrappers/package.json2
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts6
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts3
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts13
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts3
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts13
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts11
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts4
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts6
-rw-r--r--packages/contract-wrappers/src/utils/utils.ts4
-rw-r--r--packages/contracts/package.json2
-rw-r--r--packages/dev-tools-pages/package.json2
-rw-r--r--packages/dev-utils/package.json2
-rw-r--r--packages/ethereum-types/package.json2
-rw-r--r--packages/fill-scenarios/package.json2
-rw-r--r--packages/instant/package.json2
-rw-r--r--packages/instant/src/components/buy_order_state_button.tsx26
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx63
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx5
-rw-r--r--packages/instant/src/components/retry_button.tsx11
-rw-r--r--packages/instant/src/components/scaling_amount_input.tsx3
-rw-r--r--packages/instant/src/components/scaling_input.tsx5
-rw-r--r--packages/instant/src/components/secondary_button.tsx5
-rw-r--r--packages/instant/src/components/ui/button.tsx1
-rw-r--r--packages/instant/src/components/view_transaction_button.tsx11
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx4
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_button.tsx20
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts (renamed from packages/instant/src/containers/selected_asset_buy_button.ts)44
-rw-r--r--packages/instant/src/containers/selected_asset_retry_button.tsx26
-rw-r--r--packages/instant/src/containers/selected_asset_view_transaction_button.tsx38
-rw-r--r--packages/instant/src/containers/selected_erc20_asset_amount_input.ts10
-rw-r--r--packages/instant/src/redux/reducer.ts47
-rw-r--r--packages/json-schemas/package.json2
-rw-r--r--packages/metacoin/package.json2
-rw-r--r--packages/migrations/package.json2
-rw-r--r--packages/monorepo-scripts/package.json2
-rw-r--r--packages/order-utils/package.json2
-rw-r--r--packages/order-utils/test/asset_data_utils_test.ts25
-rw-r--r--packages/order-watcher/package.json2
-rw-r--r--packages/react-docs/package.json2
-rw-r--r--packages/react-shared/package.json2
-rw-r--r--packages/sol-compiler/package.json2
-rw-r--r--packages/sol-cov/package.json2
-rw-r--r--packages/sol-doc/package.json2
-rw-r--r--packages/sol-resolver/package.json2
-rw-r--r--packages/sra-spec/package.json2
-rw-r--r--packages/subproviders/package.json2
-rw-r--r--packages/testnet-faucets/package.json2
-rw-r--r--packages/tslint-config/package.json2
-rw-r--r--packages/types/package.json2
-rw-r--r--packages/utils/package.json2
-rw-r--r--packages/web3-wrapper/package.json2
-rw-r--r--packages/website/package.json2
-rwxr-xr-xpython-packages/order_utils/setup.py2
-rw-r--r--python-packages/order_utils/src/index.rst4
-rw-r--r--python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py15
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py77
-rw-r--r--python-packages/order_utils/test/test_asset_data_utils.py39
66 files changed, 398 insertions, 223 deletions
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index 56999d3e5..bfc29128c 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -18,7 +18,7 @@
"build": "yarn build:all",
"build:ci": "yarn build:commonjs",
"build:all": "run-p build:umd:prod build:commonjs",
- "lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*",
+ "lint": "tslint --format stylish --project .",
"test:circleci": "run-s test:coverage",
"rebuild_and_test": "run-s build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json
index 313cc339d..b8010a8a7 100644
--- a/packages/abi-gen-wrappers/package.json
+++ b/packages/abi-gen-wrappers/package.json
@@ -12,7 +12,7 @@
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"pre_build": "yarn generate_contract_wrappers",
"clean": "shx rm -rf lib wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated-wrappers --backend ethers"
diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json
index f32bb3a31..c78d4f269 100644
--- a/packages/abi-gen/package.json
+++ b/packages/abi-gen/package.json
@@ -8,7 +8,7 @@
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"clean": "shx rm -rf lib",
"build": "tsc -b",
"build:ci": "yarn build",
diff --git a/packages/assert/package.json b/packages/assert/package.json
index 37af8979d..a96f65258 100644
--- a/packages/assert/package.json
+++ b/packages/assert/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib test_temp",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test",
diff --git a/packages/asset-buyer/package.json b/packages/asset-buyer/package.json
index e4b4d19c0..dd0668632 100644
--- a/packages/asset-buyer/package.json
+++ b/packages/asset-buyer/package.json
@@ -10,7 +10,7 @@
"scripts": {
"build": "yarn tsc -b",
"build:ci": "yarn build",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json
index 676e8aab9..520dff5f9 100644
--- a/packages/base-contract/package.json
+++ b/packages/base-contract/package.json
@@ -17,7 +17,7 @@
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "lint": "tslint --project . --exclude **/src/contract_wrappers/**/*"
+ "lint": "tslint --format stylish --project ."
},
"license": "Apache-2.0",
"repository": {
diff --git a/packages/connect/package.json b/packages/connect/package.json
index 95b1bbd7d..de846e58b 100644
--- a/packages/connect/package.json
+++ b/packages/connect/package.json
@@ -19,7 +19,7 @@
"build:ci": "yarn build",
"clean": "shx rm -rf lib test_temp generated_docs",
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit",
"test": "run-s copy_test_fixtures run_mocha",
"rebuild_and_test": "run-s clean build test",
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index c3d986b4a..9ff372e33 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "3.0.1",
+ "changes": [
+ {
+ "note": "Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized.",
+ "pr": 1178
+ }
+ ]
+ },
+ {
"version": "3.0.0",
"changes": [
{
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index d427bb628..178675763 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -13,7 +13,7 @@
"scripts": {
"build": "tsc -b",
"build:ci": "yarn build",
- "lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
+ "lint": "tslint --format stylish --project . --exclude **/lib/**/*",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
diff --git a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
index 7b11f35bc..749aaae10 100644
--- a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
@@ -28,10 +28,10 @@ export abstract class ContractWrapper {
protected _networkId: number;
protected _web3Wrapper: Web3Wrapper;
private _blockAndLogStreamerIfExists: BlockAndLogStreamer<Block, Log> | undefined;
- private _blockPollingIntervalMs: number;
+ private readonly _blockPollingIntervalMs: number;
private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
- private _filters: { [filterToken: string]: FilterObject };
- private _filterCallbacks: {
+ private readonly _filters: { [filterToken: string]: FilterObject };
+ private readonly _filterCallbacks: {
[filterToken: string]: EventCallback<ContractEventArgs>;
};
private _onLogAddedSubscriptionToken: string | undefined;
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts
index adf8c7614..45460bd6d 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts
@@ -34,6 +34,9 @@ export class ERC20ProxyWrapper extends ContractWrapper {
*/
public async getProxyIdAsync(): Promise<AssetProxyId> {
const ERC20ProxyContractInstance = this._getERC20ProxyContract();
+ // Note(albrow): Below is a TSLint false positive. Code won't compile if
+ // you remove the type assertion.
+ /* tslint:disable-next-line:no-unnecessary-type-assertion */
const proxyId = (await ERC20ProxyContractInstance.getProxyId.callAsync()) as AssetProxyId;
return proxyId;
}
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts
index f5fc63b42..5e0ec1951 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts
@@ -18,12 +18,11 @@ import {
} from '../types';
import { assert } from '../utils/assert';
import { constants } from '../utils/constants';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ERC20ProxyWrapper } from './erc20_proxy_wrapper';
-const removeUndefinedProperties = _.pickBy;
-
/**
* This class includes all the functionality related to interacting with ERC20 token contracts.
* All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances
@@ -32,8 +31,8 @@ const removeUndefinedProperties = _.pickBy;
export class ERC20TokenWrapper extends ContractWrapper {
public abi: ContractAbi = ERC20Token.compilerOutput.abi;
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- private _tokenContractsByAddress: { [address: string]: ERC20TokenContract };
- private _erc20ProxyWrapper: ERC20ProxyWrapper;
+ private readonly _tokenContractsByAddress: { [address: string]: ERC20TokenContract };
+ private readonly _erc20ProxyWrapper: ERC20ProxyWrapper;
/**
* Instantiate ERC20TokenWrapper
* @param web3Wrapper Web3Wrapper instance to use
@@ -108,7 +107,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.approve.sendTransactionAsync(
normalizedSpenderAddress,
amountInBaseUnits,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedOwnerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
@@ -278,7 +277,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.transfer.sendTransactionAsync(
normalizedToAddress,
amountInBaseUnits,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedFromAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
@@ -339,7 +338,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
normalizedFromAddress,
normalizedToAddress,
amountInBaseUnits,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedSenderAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts
index 9f3a6930b..12758e191 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts
@@ -34,6 +34,9 @@ export class ERC721ProxyWrapper extends ContractWrapper {
*/
public async getProxyIdAsync(): Promise<AssetProxyId> {
const ERC721ProxyContractInstance = await this._getERC721ProxyContract();
+ // Note(albrow): Below is a TSLint false positive. Code won't compile if
+ // you remove the type assertion.
+ /* tslint:disable-next-line:no-unnecessary-type-assertion */
const proxyId = (await ERC721ProxyContractInstance.getProxyId.callAsync()) as AssetProxyId;
return proxyId;
}
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts
index 1c4b61c0b..1610af47b 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts
@@ -18,12 +18,11 @@ import {
} from '../types';
import { assert } from '../utils/assert';
import { constants } from '../utils/constants';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ERC721ProxyWrapper } from './erc721_proxy_wrapper';
-const removeUndefinedProperties = _.pickBy;
-
/**
* This class includes all the functionality related to interacting with ERC721 token contracts.
* All ERC721 method calls are supported, along with some convenience methods for getting/setting allowances
@@ -31,8 +30,8 @@ const removeUndefinedProperties = _.pickBy;
*/
export class ERC721TokenWrapper extends ContractWrapper {
public abi: ContractAbi = ERC721Token.compilerOutput.abi;
- private _tokenContractsByAddress: { [address: string]: ERC721TokenContract };
- private _erc721ProxyWrapper: ERC721ProxyWrapper;
+ private readonly _tokenContractsByAddress: { [address: string]: ERC721TokenContract };
+ private readonly _erc721ProxyWrapper: ERC721ProxyWrapper;
/**
* Instantiate ERC721TokenWrapper
* @param web3Wrapper Web3Wrapper instance to use
@@ -235,7 +234,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.setApprovalForAll.sendTransactionAsync(
normalizedOperatorAddress,
isApproved,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
from: normalizedOwnerAddress,
@@ -295,7 +294,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.approve.sendTransactionAsync(
normalizedApprovedAddress,
tokenId,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
from: tokenOwnerAddress,
@@ -366,7 +365,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
ownerAddress,
normalizedReceiverAddress,
tokenId,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
from: normalizedSenderAddress,
diff --git a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts
index d4a08da86..913c47cf7 100644
--- a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts
@@ -8,22 +8,21 @@ import * as _ from 'lodash';
import { BlockRange, ContractWrappersError, EventCallback, IndexedFilterValues, TransactionOpts } from '../types';
import { assert } from '../utils/assert';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ERC20TokenWrapper } from './erc20_token_wrapper';
-const removeUndefinedProperties = _.pickBy;
-
/**
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
*/
export class EtherTokenWrapper extends ContractWrapper {
public abi: ContractAbi = WETH9.compilerOutput.abi;
- private _etherTokenContractsByAddress: {
+ private readonly _etherTokenContractsByAddress: {
[address: string]: WETH9Contract;
} = {};
- private _erc20TokenWrapper: ERC20TokenWrapper;
+ private readonly _erc20TokenWrapper: ERC20TokenWrapper;
/**
* Instantiate EtherTokenWrapper.
* @param web3Wrapper Web3Wrapper instance to use
@@ -67,7 +66,7 @@ export class EtherTokenWrapper extends ContractWrapper {
const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
const txHash = await wethContract.deposit.sendTransactionAsync(
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedDepositorAddress,
value: amountInWei,
gas: txOpts.gasLimit,
@@ -109,7 +108,7 @@ export class EtherTokenWrapper extends ContractWrapper {
const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
const txHash = await wethContract.withdraw.sendTransactionAsync(
amountInWei,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedWithdrawerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
index 907d25aa0..2e978f35b 100644
--- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
@@ -46,8 +46,8 @@ export class ExchangeWrapper extends ContractWrapper {
public address: string;
public zrxTokenAddress: string;
private _exchangeContractIfExists?: ExchangeContract;
- private _erc721TokenWrapper: ERC721TokenWrapper;
- private _erc20TokenWrapper: ERC20TokenWrapper;
+ private readonly _erc721TokenWrapper: ERC721TokenWrapper;
+ private readonly _erc20TokenWrapper: ERC20TokenWrapper;
/**
* Instantiate ExchangeWrapper
* @param web3Wrapper Web3Wrapper instance to use.
diff --git a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
index 9463a6849..80742e030 100644
--- a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
@@ -1,7 +1,7 @@
import { ForwarderContract } from '@0x/abi-gen-wrappers';
import { Forwarder } from '@0x/contract-artifacts';
import { schemas } from '@0x/json-schemas';
-import { AssetProxyId, SignedOrder } from '@0x/types';
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi } from 'ethereum-types';
@@ -118,7 +118,7 @@ export class ForwarderWrapper extends ContractWrapper {
optimizedFeeOrders,
feeSignatures,
formattedFeePercentage,
- feeRecipientAddress,
+ normalizedFeeRecipientAddress,
{
value: ethAmount,
from: normalizedTakerAddress,
@@ -207,7 +207,7 @@ export class ForwarderWrapper extends ContractWrapper {
optimizedFeeOrders,
feeSignatures,
formattedFeePercentage,
- feeRecipientAddress,
+ normalizedFeeRecipientAddress,
{
value: ethAmount,
from: normalizedTakerAddress,
diff --git a/packages/contract-wrappers/src/utils/utils.ts b/packages/contract-wrappers/src/utils/utils.ts
index fbacdaa28..0b3270e78 100644
--- a/packages/contract-wrappers/src/utils/utils.ts
+++ b/packages/contract-wrappers/src/utils/utils.ts
@@ -1,5 +1,6 @@
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as _ from 'lodash';
import { constants } from './constants';
@@ -14,4 +15,7 @@ export const utils = {
numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber {
return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).mul(percentage);
},
+ removeUndefinedProperties<T extends object>(obj: T): Partial<T> {
+ return _.pickBy(obj);
+ },
};
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index 3a5f12c74..4f24310e8 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -23,7 +23,7 @@
"compile": "sol-compiler --contracts-dir contracts",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
- "lint": "tslint --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
+ "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json
index 3563b4bef..ca13c1cc8 100644
--- a/packages/dev-tools-pages/package.json
+++ b/packages/dev-tools-pages/package.json
@@ -11,7 +11,7 @@
"build:ci": "yarn build",
"build:dev": "../../node_modules/.bin/webpack --mode development",
"clean": "shx rm -f public/bundle*",
- "lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
+ "lint": "tslint --format stylish --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
"dev": "webpack-dev-server --mode development --content-base public"
},
"license": "Apache-2.0",
diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json
index d1b1efc87..7c6bfde90 100644
--- a/packages/dev-utils/package.json
+++ b/packages/dev-utils/package.json
@@ -17,7 +17,7 @@
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"clean": "shx rm -rf lib",
- "lint": "tslint --project ."
+ "lint": "tslint --format stylish --project ."
},
"license": "Apache-2.0",
"repository": {
diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json
index d24e39dfd..49b093bdd 100644
--- a/packages/ethereum-types/package.json
+++ b/packages/ethereum-types/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib generated_docs",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json
index 0e1303259..ae7fa02ad 100644
--- a/packages/fill-scenarios/package.json
+++ b/packages/fill-scenarios/package.json
@@ -8,7 +8,7 @@
"build": "yarn tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib src/generated_contract_wrappers",
- "lint": "tslint --project ."
+ "lint": "tslint --format stylish --project ."
},
"license": "Apache-2.0",
"repository": {
diff --git a/packages/instant/package.json b/packages/instant/package.json
index 977126867..81d2e4c7b 100644
--- a/packages/instant/package.json
+++ b/packages/instant/package.json
@@ -16,7 +16,7 @@
"build:ci": "yarn build",
"watch_without_deps": "tsc -w",
"dev": "webpack-dev-server --mode development",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test": "jest",
"test:coverage": "jest --coverage",
"rebuild_and_test": "run-s clean build test",
diff --git a/packages/instant/src/components/buy_order_state_button.tsx b/packages/instant/src/components/buy_order_state_button.tsx
deleted file mode 100644
index 44115e5a1..000000000
--- a/packages/instant/src/components/buy_order_state_button.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as React from 'react';
-
-import { PlacingOrderButton } from '../components/placing_order_button';
-import { SelectedAssetBuyButton } from '../containers/selected_asset_buy_button';
-import { SelectedAssetRetryButton } from '../containers/selected_asset_retry_button';
-import { SelectedAssetViewTransactionButton } from '../containers/selected_asset_view_transaction_button';
-import { OrderProcessState } from '../types';
-
-export interface BuyOrderStateButtonProps {
- buyOrderProcessingState: OrderProcessState;
-}
-
-export const BuyOrderStateButton: React.StatelessComponent<BuyOrderStateButtonProps> = props => {
- if (props.buyOrderProcessingState === OrderProcessState.FAILURE) {
- return <SelectedAssetRetryButton />;
- } else if (
- props.buyOrderProcessingState === OrderProcessState.SUCCESS ||
- props.buyOrderProcessingState === OrderProcessState.PROCESSING
- ) {
- return <SelectedAssetViewTransactionButton />;
- } else if (props.buyOrderProcessingState === OrderProcessState.AWAITING_SIGNATURE) {
- return <PlacingOrderButton />;
- }
-
- return <SelectedAssetBuyButton />;
-};
diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx
new file mode 100644
index 000000000..758eabcb7
--- /dev/null
+++ b/packages/instant/src/components/buy_order_state_buttons.tsx
@@ -0,0 +1,63 @@
+import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
+import * as React from 'react';
+
+import { BuyButton } from '../components/buy_button';
+import { SecondaryButton } from '../components/secondary_button';
+import { Flex } from '../components/ui/flex';
+
+import { PlacingOrderButton } from '../components/placing_order_button';
+import { ColorOption } from '../style/theme';
+import { OrderProcessState } from '../types';
+
+import { Button } from './ui/button';
+import { Text } from './ui/text';
+
+export interface BuyOrderStateButtonProps {
+ buyQuote?: BuyQuote;
+ buyOrderProcessingState: OrderProcessState;
+ assetBuyer?: AssetBuyer;
+ onViewTransaction: () => void;
+ onAwaitingSignature: (buyQuote: BuyQuote) => void;
+ onSignatureDenied: (buyQuote: BuyQuote) => void;
+ onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void;
+ onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void;
+ onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void;
+ onRetry: () => void;
+}
+
+// TODO: rename to buttons
+export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonProps> = props => {
+ if (props.buyOrderProcessingState === OrderProcessState.FAILURE) {
+ return (
+ <Flex justify="space-between">
+ <Button width="48%" onClick={props.onRetry}>
+ <Text fontColor={ColorOption.white} fontWeight={600} fontSize="16px">
+ Back
+ </Text>
+ </Button>
+ <SecondaryButton width="48%" onClick={props.onViewTransaction}>
+ Details
+ </SecondaryButton>
+ </Flex>
+ );
+ } else if (
+ props.buyOrderProcessingState === OrderProcessState.SUCCESS ||
+ props.buyOrderProcessingState === OrderProcessState.PROCESSING
+ ) {
+ return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>;
+ } else if (props.buyOrderProcessingState === OrderProcessState.AWAITING_SIGNATURE) {
+ return <PlacingOrderButton />;
+ }
+
+ return (
+ <BuyButton
+ buyQuote={props.buyQuote}
+ assetBuyer={props.assetBuyer}
+ onAwaitingSignature={props.onAwaitingSignature}
+ onSignatureDenied={props.onSignatureDenied}
+ onBuyProcessing={props.onBuyProcessing}
+ onBuySuccess={props.onBuySuccess}
+ onBuyFailure={props.onBuyFailure}
+ />
+ );
+};
diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx
index 583fad28b..5abb34c2f 100644
--- a/packages/instant/src/components/erc20_asset_amount_input.tsx
+++ b/packages/instant/src/components/erc20_asset_amount_input.tsx
@@ -17,6 +17,7 @@ export interface ERC20AssetAmountInputProps {
onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void;
startingFontSizePx: number;
fontColor?: ColorOption;
+ isDisabled: boolean;
}
export interface ERC20AssetAmountInputState {
@@ -26,6 +27,7 @@ export interface ERC20AssetAmountInputState {
export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> {
public static defaultProps = {
onChange: util.boundNoop,
+ isDisabled: false,
};
constructor(props: ERC20AssetAmountInputProps) {
super(props);
@@ -35,9 +37,10 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
}
public render(): React.ReactNode {
const { asset, onChange, ...rest } = this.props;
+ const amountBorderBottom = this.props.isDisabled ? '' : `1px solid ${transparentWhite}`;
return (
<Container whiteSpace="nowrap">
- <Container borderBottom={`1px solid ${transparentWhite}`} display="inline-block">
+ <Container borderBottom={amountBorderBottom} display="inline-block">
<ScalingAmountInput
{...rest}
textLengthThreshold={this._textLengthThresholdForAsset(asset)}
diff --git a/packages/instant/src/components/retry_button.tsx b/packages/instant/src/components/retry_button.tsx
deleted file mode 100644
index 0d6188e6a..000000000
--- a/packages/instant/src/components/retry_button.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import * as React from 'react';
-
-import { SecondaryButton } from './secondary_button';
-
-export interface RetryButtonProps {
- onClick: () => void;
-}
-
-export const RetryButton: React.StatelessComponent<RetryButtonProps> = props => {
- return <SecondaryButton onClick={props.onClick}>Try Again</SecondaryButton>;
-};
diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx
index 655ae2b74..cfbf3b7cc 100644
--- a/packages/instant/src/components/scaling_amount_input.tsx
+++ b/packages/instant/src/components/scaling_amount_input.tsx
@@ -8,6 +8,7 @@ import { util } from '../util/util';
import { ScalingInput } from './scaling_input';
export interface ScalingAmountInputProps {
+ isDisabled: boolean;
maxFontSizePx: number;
textLengthThreshold: number;
fontColor?: ColorOption;
@@ -20,6 +21,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps>
public static defaultProps = {
onChange: util.boundNoop,
onFontSizeChange: util.boundNoop,
+ isDisabled: false,
};
public render(): React.ReactNode {
const { textLengthThreshold, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props;
@@ -33,6 +35,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps>
value={!_.isUndefined(value) ? value.toDisplayString() : ''}
placeholder="0.00"
emptyInputWidthCh={3.5}
+ isDisabled={this.props.isDisabled}
/>
);
}
diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 34cb0b5fd..11748b729 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -27,6 +27,7 @@ export interface ScalingInputProps {
placeholder?: string;
maxLength?: number;
scalingSettings: ScalingSettings;
+ isDisabled: boolean;
}
export interface ScalingInputState {
@@ -49,6 +50,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
onFontSizeChange: util.boundNoop,
maxLength: 7,
scalingSettings: defaultScalingSettings,
+ isDisabled: false,
};
public state: ScalingInputState = {
inputWidthPxAtPhaseChange: undefined,
@@ -121,7 +123,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
}
}
public render(): React.ReactNode {
- const { fontColor, onChange, placeholder, value, maxLength } = this.props;
+ const { isDisabled, fontColor, onChange, placeholder, value, maxLength } = this.props;
const phase = ScalingInput.getPhaseFromProps(this.props);
return (
<Input
@@ -133,6 +135,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
fontSize={`${this._calculateFontSize(phase)}px`}
width={this._calculateWidth(phase)}
maxLength={maxLength}
+ disabled={isDisabled}
/>
);
}
diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx
index 3c139a233..583058b5b 100644
--- a/packages/instant/src/components/secondary_button.tsx
+++ b/packages/instant/src/components/secondary_button.tsx
@@ -14,7 +14,7 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p
<Button
backgroundColor={ColorOption.white}
borderColor={ColorOption.lightGrey}
- width="100%"
+ width={props.width}
onClick={props.onClick}
{...buttonProps}
>
@@ -24,3 +24,6 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p
</Button>
);
};
+SecondaryButton.defaultProps = {
+ width: '100%',
+};
diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx
index 1fcb2591c..5274d835b 100644
--- a/packages/instant/src/components/ui/button.tsx
+++ b/packages/instant/src/components/ui/button.tsx
@@ -52,6 +52,7 @@ export const Button = styled(PlainButton)`
Button.defaultProps = {
backgroundColor: ColorOption.primaryColor,
+ borderColor: ColorOption.primaryColor,
width: 'auto',
isDisabled: false,
padding: '1em 2.2em',
diff --git a/packages/instant/src/components/view_transaction_button.tsx b/packages/instant/src/components/view_transaction_button.tsx
deleted file mode 100644
index 7aa44e657..000000000
--- a/packages/instant/src/components/view_transaction_button.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import * as React from 'react';
-
-import { SecondaryButton } from './secondary_button';
-
-export interface ViewTransactionButtonProps {
- onClick: () => void;
-}
-
-export const ViewTransactionButton: React.StatelessComponent<ViewTransactionButtonProps> = props => {
- return <SecondaryButton onClick={props.onClick}>View Transaction</SecondaryButton>;
-};
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index 1d17ed12a..ff19351ff 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
import { LatestError } from '../containers/latest_error';
-import { SelectedAssetBuyOrderStateButton } from '../containers/selected_asset_buy_order_state_button';
+import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons';
import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
import { ColorOption } from '../style/theme';
@@ -27,7 +27,7 @@ export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantConta
<SelectedAssetInstantHeading />
<LatestBuyQuoteOrderDetails />
<Container padding="20px" width="100%">
- <SelectedAssetBuyOrderStateButton />
+ <SelectedAssetBuyOrderStateButtons />
</Container>
</Flex>
</Container>
diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_button.tsx b/packages/instant/src/containers/selected_asset_buy_order_state_button.tsx
deleted file mode 100644
index 7faa79912..000000000
--- a/packages/instant/src/containers/selected_asset_buy_order_state_button.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import { connect } from 'react-redux';
-
-import { State } from '../redux/reducer';
-import { OrderProcessState } from '../types';
-
-import { BuyOrderStateButton } from '../components/buy_order_state_button';
-
-interface ConnectedState {
- buyOrderProcessingState: OrderProcessState;
-}
-export interface SelectedAssetButtonProps {}
-const mapStateToProps = (state: State, _ownProps: SelectedAssetButtonProps): ConnectedState => ({
- buyOrderProcessingState: state.buyOrderState.processState,
-});
-
-export const SelectedAssetBuyOrderStateButton: React.ComponentClass<SelectedAssetButtonProps> = connect(
- mapStateToProps,
-)(BuyOrderStateButton);
diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
index 377831b43..10734df96 100644
--- a/packages/instant/src/containers/selected_asset_buy_button.ts
+++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
@@ -8,14 +8,15 @@ import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { OrderProcessState, OrderState } from '../types';
import { errorFlasher } from '../util/error_flasher';
+import { etherscanUtil } from '../util/etherscan';
-import { BuyButton } from '../components/buy_button';
-
-export interface SelectedAssetBuyButtonProps {}
+import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
interface ConnectedState {
- assetBuyer?: AssetBuyer;
buyQuote?: BuyQuote;
+ buyOrderProcessingState: OrderProcessState;
+ assetBuyer?: AssetBuyer;
+ onViewTransaction: () => void;
}
interface ConnectedDispatch {
@@ -24,14 +25,36 @@ interface ConnectedDispatch {
onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void;
onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void;
onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void;
+ onRetry: () => void;
}
-
-const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps): ConnectedState => ({
+export interface SelectedAssetBuyOrderStateButtons {}
+const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({
+ buyOrderProcessingState: state.buyOrderState.processState,
assetBuyer: state.assetBuyer,
buyQuote: state.latestBuyQuote,
+ onViewTransaction: () => {
+ if (
+ state.assetBuyer &&
+ (state.buyOrderState.processState === OrderProcessState.PROCESSING ||
+ state.buyOrderState.processState === OrderProcessState.SUCCESS ||
+ state.buyOrderState.processState === OrderProcessState.FAILURE)
+ ) {
+ const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists(
+ state.buyOrderState.txHash,
+ state.assetBuyer.networkId,
+ );
+ if (etherscanUrl) {
+ window.open(etherscanUrl, '_blank');
+ return;
+ }
+ }
+ },
});
-const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({
+const mapDispatchToProps = (
+ dispatch: Dispatch<Action>,
+ ownProps: SelectedAssetBuyOrderStateButtons,
+): ConnectedDispatch => ({
onAwaitingSignature: (buyQuote: BuyQuote) => {
const newOrderState: OrderState = { processState: OrderProcessState.AWAITING_SIGNATURE };
dispatch(actions.updateBuyOrderState(newOrderState));
@@ -49,9 +72,12 @@ const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetB
const errorMessage = 'You denied this transaction';
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
},
+ onRetry: () => {
+ dispatch(actions.resetAmount());
+ },
});
-export const SelectedAssetBuyButton: React.ComponentClass<SelectedAssetBuyButtonProps> = connect(
+export const SelectedAssetBuyOrderStateButtons: React.ComponentClass<SelectedAssetBuyOrderStateButtons> = connect(
mapStateToProps,
mapDispatchToProps,
-)(BuyButton);
+)(BuyOrderStateButtons);
diff --git a/packages/instant/src/containers/selected_asset_retry_button.tsx b/packages/instant/src/containers/selected_asset_retry_button.tsx
deleted file mode 100644
index b2b140be6..000000000
--- a/packages/instant/src/containers/selected_asset_retry_button.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Dispatch } from 'redux';
-
-import { Action, actions } from '../redux/actions';
-
-import { RetryButton } from '../components/retry_button';
-
-export interface SelectedAssetRetryButtonProps {}
-
-interface ConnectedDispatch {
- onClick: () => void;
-}
-
-const mapDispatchToProps = (
- dispatch: Dispatch<Action>,
- _ownProps: SelectedAssetRetryButtonProps,
-): ConnectedDispatch => ({
- onClick: () => dispatch(actions.resetAmount()),
-});
-
-export const SelectedAssetRetryButton: React.ComponentClass<SelectedAssetRetryButtonProps> = connect(
- undefined,
- mapDispatchToProps,
-)(RetryButton);
diff --git a/packages/instant/src/containers/selected_asset_view_transaction_button.tsx b/packages/instant/src/containers/selected_asset_view_transaction_button.tsx
deleted file mode 100644
index 064b877be..000000000
--- a/packages/instant/src/containers/selected_asset_view_transaction_button.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import { connect } from 'react-redux';
-
-import { State } from '../redux/reducer';
-
-import { ViewTransactionButton } from '../components/view_transaction_button';
-import { OrderProcessState } from '../types';
-import { etherscanUtil } from '../util/etherscan';
-
-export interface SelectedAssetViewTransactionButtonProps {}
-
-interface ConnectedState {
- onClick: () => void;
-}
-
-const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({
- onClick: () => {
- if (
- state.assetBuyer &&
- (state.buyOrderState.processState === OrderProcessState.PROCESSING ||
- state.buyOrderState.processState === OrderProcessState.SUCCESS)
- ) {
- const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists(
- state.buyOrderState.txHash,
- state.assetBuyer.networkId,
- );
- if (etherscanUrl) {
- window.open(etherscanUrl, '_blank');
- return;
- }
- }
- },
-});
-
-export const SelectedAssetViewTransactionButton: React.ComponentClass<
- SelectedAssetViewTransactionButtonProps
-> = connect(mapStateToProps)(ViewTransactionButton);
diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
index 8fcb430a7..1e93a6deb 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -26,6 +26,7 @@ interface ConnectedState {
assetBuyer?: AssetBuyer;
value?: BigNumberInput;
asset?: ERC20Asset;
+ isDisabled: boolean;
}
interface ConnectedDispatch {
@@ -36,21 +37,29 @@ interface ConnectedProps {
value?: BigNumberInput;
asset?: ERC20Asset;
onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void;
+ isDisabled: boolean;
}
type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps;
const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => {
+ const processState = state.buyOrderState.processState;
+ const isEnabled = processState === OrderProcessState.NONE || processState === OrderProcessState.FAILURE;
+ const isDisabled = !isEnabled;
+
const selectedAsset = state.selectedAsset;
if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) {
return {
value: state.selectedAssetAmount,
+ isDisabled,
};
}
+
return {
assetBuyer: state.assetBuyer,
value: state.selectedAssetAmount,
asset: selectedAsset as ERC20Asset,
+ isDisabled,
};
};
@@ -128,6 +137,7 @@ const mergeProps = (
onChange: (value, asset) => {
connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset);
},
+ isDisabled: connectedState.isDisabled,
};
};
diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts
index 3884eeea9..dd9403052 100644
--- a/packages/instant/src/redux/reducer.ts
+++ b/packages/instant/src/redux/reducer.ts
@@ -1,6 +1,7 @@
import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
-import { ObjectMap } from '@0x/types';
+import { AssetProxyId, ObjectMap } from '@0x/types';
import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import { assetMetaDataMap } from '../data/asset_meta_data_map';
@@ -57,11 +58,19 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
selectedAssetAmount: action.data,
};
case ActionTypes.UPDATE_LATEST_BUY_QUOTE:
- return {
- ...state,
- latestBuyQuote: action.data,
- quoteRequestState: AsyncProcessState.SUCCESS,
- };
+ const newBuyQuoteIfExists = action.data;
+ const shouldUpdate =
+ _.isUndefined(newBuyQuoteIfExists) || doesBuyQuoteMatchState(newBuyQuoteIfExists, state);
+ if (shouldUpdate) {
+ return {
+ ...state,
+ latestBuyQuote: newBuyQuoteIfExists,
+ quoteRequestState: AsyncProcessState.SUCCESS,
+ };
+ } else {
+ return state;
+ }
+
case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING:
return {
...state,
@@ -122,3 +131,29 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
return state;
}
};
+
+const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => {
+ const selectedAssetIfExists = state.selectedAsset;
+ const selectedAssetAmountIfExists = state.selectedAssetAmount;
+ // if no selectedAsset or selectedAssetAmount exists on the current state, return false
+ if (_.isUndefined(selectedAssetIfExists) || _.isUndefined(selectedAssetAmountIfExists)) {
+ return false;
+ }
+ // if buyQuote's assetData does not match that of the current selected asset, return false
+ if (selectedAssetIfExists.assetData !== buyQuote.assetData) {
+ return false;
+ }
+ // if ERC20 and buyQuote's assetBuyAmount does not match selectedAssetAmount, return false
+ // if ERC721, return true
+ const selectedAssetMetaData = selectedAssetIfExists.metaData;
+ if (selectedAssetMetaData.assetProxyId === AssetProxyId.ERC20) {
+ const selectedAssetAmountBaseUnits = Web3Wrapper.toBaseUnitAmount(
+ selectedAssetAmountIfExists,
+ selectedAssetMetaData.decimals,
+ );
+ const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(buyQuote.assetBuyAmount);
+ return doesAssetAmountMatch;
+ } else {
+ return true;
+ }
+};
diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json
index 97cf607c1..57715c601 100644
--- a/packages/json-schemas/package.json
+++ b/packages/json-schemas/package.json
@@ -10,7 +10,7 @@
"scripts": {
"build": "tsc -b",
"build:ci": "yarn build",
- "lint": "tslint --project . --exclude **/schemas/**/*",
+ "lint": "tslint --format stylish --project . --exclude **/schemas/**/*",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json
index 04bdeba4c..e3432c010 100644
--- a/packages/metacoin/package.json
+++ b/packages/metacoin/package.json
@@ -7,7 +7,7 @@
"private": true,
"description": "Example solidity project using 0x dev tools",
"scripts": {
- "lint": "tslint --project . --exclude **/src/contract_wrappers/**/*",
+ "lint": "tslint --format stylish --project . --exclude **/src/contract_wrappers/**/*",
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers copy_artifacts",
diff --git a/packages/migrations/package.json b/packages/migrations/package.json
index 353697bfc..b610d3c6a 100644
--- a/packages/migrations/package.json
+++ b/packages/migrations/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"migrate:v2": "run-s build script:migrate:v2",
"script:migrate:v2": "node ./lib/migrate.js --contracts-version 2.0.0"
},
diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json
index ba5f9ca6a..a83f90516 100644
--- a/packages/monorepo-scripts/package.json
+++ b/packages/monorepo-scripts/package.json
@@ -11,7 +11,7 @@
"scripts": {
"build": "tsc -b",
"build:ci": "yarn build",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"clean": "shx rm -rf lib",
"test:publish": "run-s build script:publish",
"find_unused_deps": "run-s build script:find_unused_deps",
diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json
index 69f14a79e..a6a84b940 100644
--- a/packages/order-utils/package.json
+++ b/packages/order-utils/package.json
@@ -17,7 +17,7 @@
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"clean": "shx rm -rf lib generated_docs",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts
index f8b850604..f175b7a38 100644
--- a/packages/order-utils/test/asset_data_utils_test.ts
+++ b/packages/order-utils/test/asset_data_utils_test.ts
@@ -1,6 +1,7 @@
import * as chai from 'chai';
-import { ERC20AssetData } from '@0x/types';
+import { ERC20AssetData, ERC721AssetData } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import { assetDataUtils } from '../src/asset_data_utils';
@@ -14,18 +15,36 @@ 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';
describe('assetDataUtils', () => {
- it('should encode', () => {
+ it('should encode ERC20', () => {
const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ENCODINGS[0].address);
expect(assetData).to.equal(KNOWN_ENCODINGS[0].assetData);
});
- it('should decode', () => {
+ 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);
});
+ 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);
+ });
+ 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);
+ });
});
diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json
index acc70544e..42e3f572c 100644
--- a/packages/order-watcher/package.json
+++ b/packages/order-watcher/package.json
@@ -14,7 +14,7 @@
"scripts": {
"build": "yarn tsc -b",
"build:ci": "yarn build",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json
index d3ccfa8da..e234b0479 100644
--- a/packages/react-docs/package.json
+++ b/packages/react-docs/package.json
@@ -8,7 +8,7 @@
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib"
diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json
index 7a150bf35..45220e2d2 100644
--- a/packages/react-shared/package.json
+++ b/packages/react-shared/package.json
@@ -8,7 +8,7 @@
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"build": "tsc",
"build:ci": "yarn build",
"watch_without_deps": "tsc -w",
diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json
index 4c4370b1f..17ccb50b8 100644
--- a/packages/sol-compiler/package.json
+++ b/packages/sol-compiler/package.json
@@ -19,7 +19,7 @@
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"clean": "shx rm -rf lib generated_docs",
"migrate": "npm run build; node lib/src/cli.js migrate",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test:circleci": "yarn test:coverage",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index a56713d69..09119321d 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -11,7 +11,7 @@
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s copy_test_fixtures",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test": "run-s compile_test run_mocha",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
diff --git a/packages/sol-doc/package.json b/packages/sol-doc/package.json
index de10b9e17..b1e887fa5 100644
--- a/packages/sol-doc/package.json
+++ b/packages/sol-doc/package.json
@@ -11,7 +11,7 @@
"test:circleci": "yarn test:coverage",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "lint": "tslint --project . --format stylish",
+ "lint": "tslint --format stylish --project .",
"clean": "shx rm -rf lib",
"generate-v1-protocol-docs": "(cd ../contracts/src/1.0.0; node ../../../../node_modules/.bin/sol-doc --contracts-dir . --contracts Exchange/Exchange_v1.sol TokenRegistry/TokenRegistry.sol TokenTransferProxy/TokenTransferProxy_v1.sol) > v1.0.0.json",
"generate-v2-protocol-docs": "(cd ../contracts/src/2.0.0; node ../../../../node_modules/.bin/sol-doc --contracts-dir . --contracts Exchange/Exchange.sol AssetProxy/ERC20Proxy.sol AssetProxy/ERC721Proxy.sol OrderValidator/OrderValidator.sol Forwarder/Forwarder.sol AssetProxyOwner/AssetProxyOwner.sol) > v2.0.0.json",
diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json
index 4bd63f406..4d4d0be0e 100644
--- a/packages/sol-resolver/package.json
+++ b/packages/sol-resolver/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib",
- "lint": "tslint --project ."
+ "lint": "tslint --format stylish --project ."
},
"repository": {
"type": "git",
diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json
index 0c55465d7..2d3e7decd 100644
--- a/packages/sra-spec/package.json
+++ b/packages/sra-spec/package.json
@@ -10,7 +10,7 @@
"scripts": {
"serve": "redoc-cli serve lib/api.json --watch",
"watch_without_deps": "run-p build:watch serve",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test": "swagger-cli validate lib/api.json",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json
index 4eef09fe6..32e2bae24 100644
--- a/packages/subproviders/package.json
+++ b/packages/subproviders/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib generated_docs",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"run_mocha_unit": "mocha --require source-map-support/register --require make-promises-safe lib/test/unit/**/*_test.js --timeout 10000 --bail --exit",
"run_mocha_integration": "mocha --require source-map-support/register --require make-promises-safe lib/test/integration/**/*_test.js --timeout 10000 --bail --exit",
"test": "npm run test:unit",
diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json
index e683ae25a..53f1b95df 100644
--- a/packages/testnet-faucets/package.json
+++ b/packages/testnet-faucets/package.json
@@ -12,7 +12,7 @@
"build:ci": "yarn build",
"dev": "node ../../node_modules/gulp/bin/gulp.js run",
"start": "node ./server/server.js",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"clean": "shx rm -rf server"
},
"author": "Fabio Berger",
diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json
index 0a8c1b245..a235532fb 100644
--- a/packages/tslint-config/package.json
+++ b/packages/tslint-config/package.json
@@ -10,7 +10,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib",
- "lint": "tslint --project ."
+ "lint": "tslint --format stylish --project ."
},
"repository": {
"type": "git",
diff --git a/packages/types/package.json b/packages/types/package.json
index fdd68a486..9b3ae6701 100644
--- a/packages/types/package.json
+++ b/packages/types/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib",
- "lint": "tslint --project ."
+ "lint": "tslint --format stylish --project ."
},
"license": "Apache-2.0",
"repository": {
diff --git a/packages/utils/package.json b/packages/utils/package.json
index f89cfda17..4e0df9275 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test": "yarn run_mocha",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --bail --exit",
diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json
index 579957747..e95245df8 100644
--- a/packages/web3-wrapper/package.json
+++ b/packages/web3-wrapper/package.json
@@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib generated_docs",
- "lint": "tslint --project .",
+ "lint": "tslint --format stylish --project .",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test",
"test:circleci": "yarn test:coverage",
diff --git a/packages/website/package.json b/packages/website/package.json
index 771b1b908..efb97d309 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -10,7 +10,7 @@
"build": "node --max_old_space_size=8192 ../../node_modules/.bin/webpack --mode production",
"build:dev": "../../node_modules/.bin/webpack --mode development",
"clean": "shx rm -f public/bundle*",
- "lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
+ "lint": "tslint --format stylish --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
"dev": "webpack-dev-server --mode development --content-base public --https",
"deploy_dogfood": "npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
"deploy_staging": "npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
diff --git a/python-packages/order_utils/setup.py b/python-packages/order_utils/setup.py
index 159499ec4..22a5f4c41 100755
--- a/python-packages/order_utils/setup.py
+++ b/python-packages/order_utils/setup.py
@@ -20,7 +20,7 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
- pytest.main()
+ exit(pytest.main())
# pylint: disable=too-many-ancestors
diff --git a/python-packages/order_utils/src/index.rst b/python-packages/order_utils/src/index.rst
index 9c26b7924..22d5b0ef9 100644
--- a/python-packages/order_utils/src/index.rst
+++ b/python-packages/order_utils/src/index.rst
@@ -15,7 +15,9 @@ Python zero_ex.order_utils
.. autoclass:: zero_ex.order_utils.asset_data_utils.ERC20AssetData
-See source for properties. Sphinx does not easily generate class property docs; pull requests welcome.
+.. autoclass:: zero_ex.order_utils.asset_data_utils.ERC721AssetData
+
+See source for class properties. Sphinx does not easily generate class property docs; pull requests welcome.
Indices and tables
==================
diff --git a/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py b/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py
index 745d014e6..a100da567 100644
--- a/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py
+++ b/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py
@@ -31,3 +31,18 @@ def assert_is_list(value: Any, name: str) -> None:
f"expected variable '{name}', with value {str(value)}, to have"
+ f" type 'list', not '{type(value).__name__}'"
)
+
+
+def assert_is_int(value: Any, name: str) -> None:
+ """If :param value: isn't of type int, raise a TypeError.
+
+ >>> try: assert_is_int('asdf', 'var')
+ ... except TypeError as type_error: print(str(type_error))
+ ...
+ expected variable 'var', with value asdf, to have type 'int', not 'str'
+ """
+ if not isinstance(value, int):
+ raise TypeError(
+ f"expected variable '{name}', with value {str(value)}, to have"
+ + f" type 'int', not '{type(value).__name__}'"
+ )
diff --git a/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py b/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py
index 451de39af..e6f9a07c1 100644
--- a/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py
+++ b/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py
@@ -5,10 +5,11 @@ from mypy_extensions import TypedDict
import eth_abi
from zero_ex.dev_utils import abi_utils
-from zero_ex.dev_utils.type_assertions import assert_is_string
+from zero_ex.dev_utils.type_assertions import assert_is_string, assert_is_int
ERC20_ASSET_DATA_BYTE_LENGTH = 36
+ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH = 53
SELECTOR_LENGTH = 10
@@ -19,6 +20,14 @@ class ERC20AssetData(TypedDict):
token_address: str
+class ERC721AssetData(TypedDict):
+ """Object interface to ERC721 asset data."""
+
+ asset_proxy_id: str
+ token_address: str
+ token_id: int
+
+
def encode_erc20_asset_data(token_address: str) -> str:
"""Encode an ERC20 token address into an asset data string.
@@ -39,7 +48,7 @@ def encode_erc20_asset_data(token_address: str) -> str:
def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
# docstring considered all one line by pylint: disable=line-too-long
- """Decode an ERC20 assetData hex string.
+ """Decode an ERC20 asset data hex string.
:param asset_data: String produced by prior call to encode_erc20_asset_data()
@@ -55,7 +64,7 @@ def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
+ f" Got {str(len(asset_data))}."
)
- asset_proxy_id: str = asset_data[0:10]
+ asset_proxy_id: str = asset_data[0:SELECTOR_LENGTH]
if asset_proxy_id != abi_utils.method_id("ERC20Token", ["address"]):
raise ValueError(
"Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be"
@@ -70,3 +79,65 @@ def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData:
)[0]
return {"asset_proxy_id": asset_proxy_id, "token_address": token_address}
+
+
+def encode_erc721_asset_data(token_address: str, token_id: int) -> str:
+ # docstring considered all one line by pylint: disable=line-too-long
+ """Encode an ERC721 asset data hex string.
+
+ :param token_address: the ERC721 token's contract address.
+ :param token_id: the identifier of the asset's instance of the token.
+ :rtype: hex encoded asset data string, usable in the makerAssetData or
+ takerAssetData fields in a 0x order.
+
+ >>> encode_erc721_asset_data('0x1dc4c1cefef38a777b15aa20260a54e584b16c48', 1)
+ '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001'
+ """ # noqa: E501 (line too long)
+ assert_is_string(token_address, "token_address")
+ assert_is_int(token_id, "token_id")
+
+ return (
+ "0x"
+ + abi_utils.simple_encode(
+ "ERC721Token(address,uint256)", token_address, token_id
+ ).hex()
+ )
+
+
+def decode_erc721_asset_data(asset_data: str) -> ERC721AssetData:
+ # docstring considered all one line by pylint: disable=line-too-long
+ """Decode an ERC721 asset data hex string.
+
+ >>> decode_erc721_asset_data('0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001')
+ {'asset_proxy_id': '0x02571792', 'token_address': '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', 'token_id': 1}
+ """ # noqa: E501 (line too long)
+ assert_is_string(asset_data, "asset_data")
+
+ if len(asset_data) < ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH:
+ raise ValueError(
+ "Could not decode ERC721 Asset Data. Expected length of encoded"
+ + f"data to be at least {ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH}. "
+ + f"Got {len(asset_data)}."
+ )
+
+ asset_proxy_id: str = asset_data[0:SELECTOR_LENGTH]
+ # prefer `black` formatting. pylint: disable=C0330
+ if asset_proxy_id != abi_utils.method_id(
+ "ERC721Token", ["address", "uint256"]
+ ):
+ raise ValueError(
+ "Could not decode ERC721 Asset Data. Expected Asset Proxy Id to be"
+ + f" ERC721 ("
+ + f"{abi_utils.method_id('ERC721Token', ['address', 'uint256'])}"
+ + f"), but got {asset_proxy_id}"
+ )
+
+ (token_address, token_id) = eth_abi.decode_abi(
+ ["address", "uint256"], bytes.fromhex(asset_data[SELECTOR_LENGTH:])
+ )
+
+ return {
+ "asset_proxy_id": asset_proxy_id,
+ "token_address": token_address,
+ "token_id": token_id,
+ }
diff --git a/python-packages/order_utils/test/test_asset_data_utils.py b/python-packages/order_utils/test/test_asset_data_utils.py
index eeada5873..079368714 100644
--- a/python-packages/order_utils/test/test_asset_data_utils.py
+++ b/python-packages/order_utils/test/test_asset_data_utils.py
@@ -3,9 +3,12 @@
import pytest
from zero_ex.order_utils.asset_data_utils import (
- encode_erc20_asset_data,
decode_erc20_asset_data,
+ decode_erc721_asset_data,
+ encode_erc20_asset_data,
+ encode_erc721_asset_data,
ERC20_ASSET_DATA_BYTE_LENGTH,
+ ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH,
)
@@ -33,3 +36,37 @@ def test_decode_erc20_asset_data_invalid_proxy_id():
decode_erc20_asset_data(
"0xffffffff" + (" " * ERC20_ASSET_DATA_BYTE_LENGTH)
)
+
+
+def test_encode_erc721_asset_data_type_error_on_token_address():
+ """Test that passing a non-string for token_address raises a TypeError."""
+ with pytest.raises(TypeError):
+ encode_erc721_asset_data(123, 123)
+
+
+def test_encode_erc721_asset_data_type_error_on_token_id():
+ """Test that passing a non-int for token_id raises a TypeError."""
+ with pytest.raises(TypeError):
+ encode_erc721_asset_data("asdf", "asdf")
+
+
+def test_decode_erc721_asset_data_type_error():
+ """Test that passing a non-string for asset_data raises a TypeError."""
+ with pytest.raises(TypeError):
+ decode_erc721_asset_data(123)
+
+
+def test_decode_erc721_asset_data_with_asset_data_too_short():
+ """Test that passing in too short of a string raises a ValueError."""
+ with pytest.raises(ValueError):
+ decode_erc721_asset_data(
+ " " * (ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH - 1)
+ )
+
+
+def test_decode_erc721_asset_data_invalid_proxy_id():
+ """Test that passing in too short of a string raises a ValueError."""
+ with pytest.raises(ValueError):
+ decode_erc721_asset_data(
+ "0xffffffff" + " " * (ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH - 1)
+ )