aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-10-29 09:36:13 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-10-29 10:07:53 +0800
commit8d1689073b702d973075d30b2bb36369487fad1c (patch)
treecb0380d4782b0715f0d24e7a9c5f88b49a60fa50
parent4f5ab1a72d33dc6a7516d7b1d51f1aa15752a6b8 (diff)
parentae6202ed3d777605a3fd02cd29141a3ba40f4b34 (diff)
downloaddexon-0x-contracts-8d1689073b702d973075d30b2bb36369487fad1c.tar.gz
dexon-0x-contracts-8d1689073b702d973075d30b2bb36369487fad1c.tar.zst
dexon-0x-contracts-8d1689073b702d973075d30b2bb36369487fad1c.zip
Merge branch 'development' into feature/instant/fixed-orders-in-render-method
* development: fix(instant): refactor some props to use isDisabled instead of disabled linting imports feat(instant): Disable input when processing Add back debounce Make doesBuyQuoteMatchState in reducer less strict fix(instant): prevent outdated quote requests from overriding the correct quote selected asset buy order state button -> selected asset buy order state buttons buy order state button -> buy order state buttons feat(order_utils.py): ERC721 asset data codec (#1186) Add note about tslint false positive tsx -> ts Get BuyOrderState one big connected component, and let user view failure Show View Transaction button on failure, and allow setting of width for Try Again button and View Txn button Added string to constants chore: Update contract-wrappers CHANGELOG.json fix(contract-wrappers): Fix tslint errors that were lingering due to misconfiguration chore: Add --format stylish to tslint
-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)
+ )