aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml5
-rw-r--r--.gitignore1
-rw-r--r--.prettierignore1
-rw-r--r--package.json2
-rw-r--r--packages/0x.js/CHANGELOG.json9
-rw-r--r--packages/0x.js/CHANGELOG.md4
-rw-r--r--packages/0x.js/package.json36
-rw-r--r--packages/abi-gen-wrappers/CHANGELOG.json9
-rw-r--r--packages/abi-gen-wrappers/CHANGELOG.md4
-rw-r--r--packages/abi-gen-wrappers/package.json14
-rw-r--r--packages/abi-gen/CHANGELOG.json9
-rw-r--r--packages/abi-gen/CHANGELOG.md4
-rw-r--r--packages/abi-gen/package.json10
-rw-r--r--packages/assert/CHANGELOG.json9
-rw-r--r--packages/assert/CHANGELOG.md4
-rw-r--r--packages/assert/package.json10
-rw-r--r--packages/asset-buyer/CHANGELOG.json7
-rw-r--r--packages/asset-buyer/CHANGELOG.md10
-rw-r--r--packages/asset-buyer/package.json26
-rw-r--r--packages/asset-buyer/src/constants.ts2
-rw-r--r--packages/base-contract/CHANGELOG.json9
-rw-r--r--packages/base-contract/CHANGELOG.md4
-rw-r--r--packages/base-contract/package.json12
-rw-r--r--packages/connect/CHANGELOG.json9
-rw-r--r--packages/connect/CHANGELOG.md4
-rw-r--r--packages/connect/package.json16
-rw-r--r--packages/contract-addresses/CHANGELOG.json3
-rw-r--r--packages/contract-addresses/CHANGELOG.md4
-rw-r--r--packages/contract-addresses/package.json2
-rw-r--r--packages/contract-artifacts/CHANGELOG.json3
-rw-r--r--packages/contract-artifacts/CHANGELOG.md4
-rw-r--r--packages/contract-artifacts/package.json2
-rw-r--r--packages/contract-wrappers/CHANGELOG.json23
-rw-r--r--packages/contract-wrappers/CHANGELOG.md6
-rw-r--r--packages/contract-wrappers/package.json34
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts8
-rw-r--r--packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts16
-rw-r--r--packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts7
-rw-r--r--packages/contract-wrappers/test/exchange_wrapper_test.ts15
-rw-r--r--packages/contracts/CHANGELOG.json115
-rw-r--r--packages/contracts/README.md2
-rw-r--r--packages/contracts/package.json28
-rw-r--r--packages/contracts/test/utils/exchange_wrapper.ts6
-rw-r--r--packages/contracts/test/utils/fill_order_combinatorial_utils.ts2
-rw-r--r--packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts13
-rw-r--r--packages/dev-tools-pages/package.json4
-rw-r--r--packages/dev-utils/CHANGELOG.json9
-rw-r--r--packages/dev-utils/CHANGELOG.md4
-rw-r--r--packages/dev-utils/package.json16
-rw-r--r--packages/ethereum-types/CHANGELOG.json9
-rw-r--r--packages/ethereum-types/CHANGELOG.md4
-rw-r--r--packages/ethereum-types/package.json4
-rw-r--r--packages/fill-scenarios/CHANGELOG.json9
-rw-r--r--packages/fill-scenarios/CHANGELOG.md4
-rw-r--r--packages/fill-scenarios/package.json22
-rw-r--r--packages/instant/.dogfood.discharge.json (renamed from packages/instant/.discharge.json)0
-rw-r--r--packages/instant/.staging.discharge.json13
-rw-r--r--packages/instant/README.md10
-rw-r--r--packages/instant/package.json29
-rw-r--r--packages/instant/public/external.css25
-rw-r--r--packages/instant/public/index.html47
-rw-r--r--packages/instant/src/components/amount_placeholder.tsx2
-rw-r--r--packages/instant/src/components/animations/position_animation.tsx68
-rw-r--r--packages/instant/src/components/animations/slide_animation.tsx13
-rw-r--r--packages/instant/src/components/buy_button.tsx42
-rw-r--r--packages/instant/src/components/buy_order_progress.tsx10
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx28
-rw-r--r--packages/instant/src/components/css_reset.tsx32
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx8
-rw-r--r--packages/instant/src/components/erc20_token_selector.tsx12
-rw-r--r--packages/instant/src/components/instant_heading.tsx20
-rw-r--r--packages/instant/src/components/order_details.tsx7
-rw-r--r--packages/instant/src/components/payment_method.tsx45
-rw-r--r--packages/instant/src/components/payment_method_dropdown.tsx44
-rw-r--r--packages/instant/src/components/placing_order_button.tsx10
-rw-r--r--packages/instant/src/components/scaling_input.tsx2
-rw-r--r--packages/instant/src/components/search_input.tsx5
-rw-r--r--packages/instant/src/components/secondary_button.tsx8
-rw-r--r--packages/instant/src/components/sliding_error.tsx41
-rw-r--r--packages/instant/src/components/sliding_panel.tsx14
-rw-r--r--packages/instant/src/components/timed_progress_bar.tsx14
-rw-r--r--packages/instant/src/components/ui/button.tsx61
-rw-r--r--packages/instant/src/components/ui/circle.tsx27
-rw-r--r--packages/instant/src/components/ui/container.tsx83
-rw-r--r--packages/instant/src/components/ui/dropdown.tsx134
-rw-r--r--packages/instant/src/components/ui/flex.tsx25
-rw-r--r--packages/instant/src/components/ui/icon.tsx27
-rw-r--r--packages/instant/src/components/ui/index.ts9
-rw-r--r--packages/instant/src/components/ui/input.tsx23
-rw-r--r--packages/instant/src/components/ui/overlay.tsx51
-rw-r--r--packages/instant/src/components/ui/text.tsx51
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx10
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx65
-rw-r--r--packages/instant/src/components/zero_ex_instant_overlay.tsx25
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx101
-rw-r--r--packages/instant/src/constants.ts20
-rw-r--r--packages/instant/src/containers/latest_buy_quote_order_details.ts2
-rw-r--r--packages/instant/src/containers/latest_error.tsx41
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts62
-rw-r--r--packages/instant/src/containers/selected_erc20_asset_amount_input.ts69
-rw-r--r--packages/instant/src/data/asset_data_network_mapping.ts8
-rw-r--r--packages/instant/src/data/asset_meta_data_map.ts2
-rw-r--r--packages/instant/src/index.umd.ts3
-rw-r--r--packages/instant/src/redux/actions.ts11
-rw-r--r--packages/instant/src/redux/async_data.ts90
-rw-r--r--packages/instant/src/redux/reducer.ts334
-rw-r--r--packages/instant/src/redux/store.ts7
-rw-r--r--packages/instant/src/style/media.ts51
-rw-r--r--packages/instant/src/style/theme.ts14
-rw-r--r--packages/instant/src/style/z_index.ts10
-rw-r--r--packages/instant/src/types.ts60
-rw-r--r--packages/instant/src/util/asset_buyer_factory.ts17
-rw-r--r--packages/instant/src/util/balance.ts13
-rw-r--r--packages/instant/src/util/buy_quote_updater.ts59
-rw-r--r--packages/instant/src/util/etherscan.ts7
-rw-r--r--packages/instant/src/util/format.ts3
-rw-r--r--packages/instant/src/util/heartbeater.ts35
-rw-r--r--packages/instant/src/util/heartbeater_factory.ts22
-rw-r--r--packages/instant/src/util/injected_provider.ts16
-rw-r--r--packages/instant/src/util/provider_factory.ts34
-rw-r--r--packages/instant/src/util/provider_state_factory.ts63
-rw-r--r--packages/json-schemas/CHANGELOG.json3
-rw-r--r--packages/json-schemas/CHANGELOG.md4
-rw-r--r--packages/json-schemas/package.json8
-rw-r--r--packages/metacoin/package.json26
-rw-r--r--packages/migrations/CHANGELOG.json9
-rw-r--r--packages/migrations/CHANGELOG.md4
-rw-r--r--packages/migrations/package.json30
-rw-r--r--packages/monorepo-scripts/package.json2
-rw-r--r--packages/order-utils/CHANGELOG.json34
-rw-r--r--packages/order-utils/CHANGELOG.md4
-rw-r--r--packages/order-utils/package.json26
-rw-r--r--packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts3
-rw-r--r--packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts3
-rw-r--r--packages/order-utils/src/order_state_utils.ts4
-rw-r--r--packages/order-utils/src/order_validation_utils.ts209
-rw-r--r--packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts7
-rw-r--r--packages/order-utils/test/order_state_utils_test.ts3
-rw-r--r--packages/order-watcher/CHANGELOG.json9
-rw-r--r--packages/order-watcher/CHANGELOG.md4
-rw-r--r--packages/order-watcher/package.json36
-rw-r--r--packages/react-docs/CHANGELOG.json9
-rw-r--r--packages/react-docs/CHANGELOG.md4
-rw-r--r--packages/react-docs/package.json12
-rw-r--r--packages/react-shared/CHANGELOG.json9
-rw-r--r--packages/react-shared/CHANGELOG.md4
-rw-r--r--packages/react-shared/package.json8
-rw-r--r--packages/sol-compiler/CHANGELOG.json9
-rw-r--r--packages/sol-compiler/CHANGELOG.md4
-rw-r--r--packages/sol-compiler/package.json22
-rw-r--r--packages/sol-cov/CHANGELOG.json9
-rw-r--r--packages/sol-cov/CHANGELOG.md4
-rw-r--r--packages/sol-cov/package.json18
-rw-r--r--packages/sol-doc/CHANGELOG.json9
-rw-r--r--packages/sol-doc/CHANGELOG.md4
-rw-r--r--packages/sol-doc/package.json12
-rw-r--r--packages/sol-resolver/CHANGELOG.json9
-rw-r--r--packages/sol-resolver/CHANGELOG.md4
-rw-r--r--packages/sol-resolver/package.json8
-rw-r--r--packages/sra-spec/CHANGELOG.json9
-rw-r--r--packages/sra-spec/CHANGELOG.md4
-rw-r--r--packages/sra-spec/package.json6
-rw-r--r--packages/sra-spec/src/json-schemas.ts2
-rw-r--r--packages/subproviders/CHANGELOG.json9
-rw-r--r--packages/subproviders/CHANGELOG.md4
-rw-r--r--packages/subproviders/package.json18
-rw-r--r--packages/testnet-faucets/package.json16
-rw-r--r--packages/tslint-config/CHANGELOG.json9
-rw-r--r--packages/tslint-config/CHANGELOG.md4
-rw-r--r--packages/tslint-config/package.json2
-rw-r--r--packages/types/CHANGELOG.json9
-rw-r--r--packages/types/CHANGELOG.md4
-rw-r--r--packages/types/package.json6
-rw-r--r--packages/typescript-typings/CHANGELOG.json9
-rw-r--r--packages/typescript-typings/CHANGELOG.md4
-rw-r--r--packages/typescript-typings/package.json4
-rw-r--r--packages/utils/CHANGELOG.json9
-rw-r--r--packages/utils/CHANGELOG.md4
-rw-r--r--packages/utils/package.json10
-rw-r--r--packages/utils/src/configured_bignumber.ts23
-rw-r--r--packages/web3-wrapper/CHANGELOG.json3
-rw-r--r--packages/web3-wrapper/CHANGELOG.md4
-rw-r--r--packages/web3-wrapper/package.json14
-rw-r--r--packages/web3-wrapper/src/web3_wrapper.ts3
-rw-r--r--packages/website/package.json33
-rw-r--r--packages/website/ts/blockchain.ts6
-rw-r--r--packages/website/ts/components/dialogs/ledger_config_dialog.tsx2
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx2
-rw-r--r--packages/website/ts/components/generate_order/asset_picker.tsx2
-rw-r--r--packages/website/ts/components/inputs/allowance_state_toggle.tsx2
-rw-r--r--packages/website/ts/components/inputs/hash_input.tsx2
-rw-r--r--packages/website/ts/components/token_balances.tsx4
-rw-r--r--packages/website/ts/components/ui/copy_icon.tsx2
-rw-r--r--packages/website/ts/components/ui/ethereum_address.tsx2
-rw-r--r--packages/website/ts/components/ui/etherscan_icon.tsx2
-rw-r--r--packages/website/ts/components/ui/help_tooltip.tsx2
-rw-r--r--packages/website/ts/components/ui/identicon.tsx2
-rw-r--r--packages/website/ts/components/ui/party.tsx2
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx2
-rw-r--r--packages/website/ts/local_storage/trade_history_storage.tsx2
-rw-r--r--packages/website/ts/pages/documentation/developers_page.tsx2
-rw-r--r--packages/website/ts/pages/documentation/doc_page.tsx4
-rw-r--r--packages/website/ts/pages/landing/landing.tsx2
-rw-r--r--packages/website/ts/utils/doc_utils.ts2
-rw-r--r--packages/website/ts/utils/error_reporter.ts2
-rw-r--r--packages/website/ts/utils/translate.ts10
-rw-r--r--packages/website/ts/utils/utils.ts2
-rw-r--r--packages/website/tsconfig.json4
-rw-r--r--python-packages/order_utils/README.md4
-rwxr-xr-xpython-packages/order_utils/setup.py47
-rw-r--r--python-packages/order_utils/src/conf.py3
-rw-r--r--python-packages/order_utils/src/index.rst3
-rw-r--r--python-packages/order_utils/src/zero_ex/contract_artifacts/__init__.py1
l---------python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts1
-rw-r--r--python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py10
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/__init__.py12
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/py.typed (renamed from python-packages/order_utils/src/zero_ex/py.typed)0
-rw-r--r--python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py88
-rw-r--r--python-packages/order_utils/stubs/setuptools/__init__.pyi4
-rw-r--r--python-packages/order_utils/stubs/web3/__init__.pyi18
-rw-r--r--python-packages/order_utils/stubs/web3/exceptions.pyi2
-rw-r--r--python-packages/order_utils/stubs/web3/utils/__init__.pyi0
-rw-r--r--python-packages/order_utils/stubs/web3/utils/datatypes.pyi3
-rw-r--r--python-packages/order_utils/test/test_doctest.py32
-rw-r--r--python-packages/order_utils/test/test_signature_utils.py128
-rw-r--r--yarn.lock77
226 files changed, 3047 insertions, 1160 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 897fca3c0..0ab512f58 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -31,7 +31,7 @@ jobs:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- - run: cd packages/website && yarn build
+ - run: cd packages/website && yarn build:prod
test-contracts-ganache:
docker:
- image: circleci/node:9
@@ -162,6 +162,9 @@ jobs:
working_directory: ~/repo
docker:
- image: circleci/python
+ - image: 0xorg/ganache-cli
+ command: |
+ ganache-cli --gasLimit 10000000 --noVMErrorsOnRPCResponse --db /snapshot --noVMErrorsOnRPCResponse -p 8545 --networkId 50 -m "concert load couple harbor equip island argue ramp clarify fence smart topic"
steps:
- checkout
- run: sudo chown -R circleci:circleci /usr/local/bin
diff --git a/.gitignore b/.gitignore
index 3276e848a..9e43f20b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,6 +99,7 @@ packages/*/scripts/
.mypy_cache
.tox
python-packages/*/build
+python-packages/*/dist
__pycache__
python-packages/*/src/*.egg-info
python-packages/*/.coverage
diff --git a/.prettierignore b/.prettierignore
index 79dec3d1f..7ef0f6735 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,6 +4,7 @@ lib
/packages/contracts/generated-artifacts
/packages/abi-gen-wrappers/src/generated-wrappers
/packages/contract-artifacts/artifacts
+/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
/packages/json-schemas/schemas
/packages/metacoin/src/contract_wrappers
/packages/metacoin/artifacts
diff --git a/package.json b/package.json
index c786e7f19..e598ac2d3 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
},
{
"path": "packages/instant/public/main.bundle.js",
- "maxSize": "500kB"
+ "maxSize": "1000kB"
}
],
"ci": {
diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json
index a404ed481..7d9cb8312 100644
--- a/packages/0x.js/CHANGELOG.json
+++ b/packages/0x.js/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.0.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "2.0.0",
"changes": [
{
diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md
index 939ada519..d312b2c9b 100644
--- a/packages/0x.js/CHANGELOG.md
+++ b/packages/0x.js/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.1 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.0.0 - _October 18, 2018_
* Add support for `eth_signTypedData`. (#1102)
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index bfc29128c..38478980f 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -1,6 +1,6 @@
{
"name": "0x.js",
- "version": "2.0.0",
+ "version": "2.0.1",
"engines": {
"node": ">=6.12"
},
@@ -42,12 +42,12 @@
},
"license": "Apache-2.0",
"devDependencies": {
- "@0x/abi-gen": "^1.0.14",
- "@0x/abi-gen-wrappers": "^1.0.1",
- "@0x/contract-addresses": "^1.0.1",
- "@0x/dev-utils": "^1.0.13",
- "@0x/migrations": "^2.0.0",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/abi-gen": "^1.0.15",
+ "@0x/abi-gen-wrappers": "^1.0.2",
+ "@0x/contract-addresses": "^1.1.0",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/migrations": "^2.0.1",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/node": "*",
@@ -73,18 +73,18 @@
"webpack": "^4.20.2"
},
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/base-contract": "^3.0.2",
- "@0x/contract-wrappers": "^3.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/order-watcher": "^2.2.0",
- "@0x/subproviders": "^2.1.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/assert": "^1.0.15",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/contract-wrappers": "^3.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/order-watcher": "^2.2.1",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/web3-provider-engine": "^14.0.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5",
"web3-provider-engine": "14.0.6"
diff --git a/packages/abi-gen-wrappers/CHANGELOG.json b/packages/abi-gen-wrappers/CHANGELOG.json
index 211d79d26..c3273536b 100644
--- a/packages/abi-gen-wrappers/CHANGELOG.json
+++ b/packages/abi-gen-wrappers/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.2",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.1",
"changes": [
diff --git a/packages/abi-gen-wrappers/CHANGELOG.md b/packages/abi-gen-wrappers/CHANGELOG.md
index df72b112c..18bd28cb8 100644
--- a/packages/abi-gen-wrappers/CHANGELOG.md
+++ b/packages/abi-gen-wrappers/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.2 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.1 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json
index b8010a8a7..a4316449f 100644
--- a/packages/abi-gen-wrappers/package.json
+++ b/packages/abi-gen-wrappers/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/abi-gen-wrappers",
- "version": "1.0.1",
+ "version": "1.0.2",
"engines": {
"node": ">=6.12"
},
@@ -30,17 +30,17 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
"devDependencies": {
- "@0x/abi-gen": "^1.0.14",
- "@0x/tslint-config": "^1.0.9",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
- "ethereum-types": "^1.1.1",
+ "@0x/abi-gen": "^1.0.15",
+ "@0x/tslint-config": "^1.0.10",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
+ "ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5",
"shx": "^0.2.2"
},
"dependencies": {
- "@0x/base-contract": "^3.0.2"
+ "@0x/base-contract": "^3.0.3"
},
"publishConfig": {
"access": "public"
diff --git a/packages/abi-gen/CHANGELOG.json b/packages/abi-gen/CHANGELOG.json
index 4bec24183..658a997f4 100644
--- a/packages/abi-gen/CHANGELOG.json
+++ b/packages/abi-gen/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.15",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.14",
"changes": [
diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md
index 61c4d8487..21fda1656 100644
--- a/packages/abi-gen/CHANGELOG.md
+++ b/packages/abi-gen/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.15 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.14 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json
index c78d4f269..5367c9c29 100644
--- a/packages/abi-gen/package.json
+++ b/packages/abi-gen/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/abi-gen",
- "version": "1.0.14",
+ "version": "1.0.15",
"engines": {
"node": ">=6.12"
},
@@ -31,10 +31,10 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
"dependencies": {
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
"chalk": "^2.3.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"glob": "^7.1.2",
"handlebars": "^4.0.11",
"lodash": "^4.17.5",
@@ -45,7 +45,7 @@
"yargs": "^10.0.3"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/glob": "5.0.35",
"@types/handlebars": "^4.0.36",
"@types/mkdirp": "^0.5.1",
diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json
index f5a77103b..82c0938cf 100644
--- a/packages/assert/CHANGELOG.json
+++ b/packages/assert/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.15",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.14",
"changes": [
diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md
index 78b5da851..7d0895eca 100644
--- a/packages/assert/CHANGELOG.md
+++ b/packages/assert/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.15 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.14 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/assert/package.json b/packages/assert/package.json
index a96f65258..cc2fdaae9 100644
--- a/packages/assert/package.json
+++ b/packages/assert/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/assert",
- "version": "1.0.14",
+ "version": "1.0.15",
"engines": {
"node": ">=6.12"
},
@@ -29,7 +29,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/valid-url": "^1.0.2",
@@ -44,9 +44,9 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/json-schemas": "^2.0.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
"lodash": "^4.17.5",
"valid-url": "^1.0.9"
},
diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json
index 0d71bb84d..df4531063 100644
--- a/packages/asset-buyer/CHANGELOG.json
+++ b/packages/asset-buyer/CHANGELOG.json
@@ -24,8 +24,13 @@
"note":
"Fix bug where default values for `AssetBuyer` public facing methods could get overriden by `undefined` values",
"pr": 1207
+ },
+ {
+ "note": "Lower default expiry buffer from 5 minutes to 2 minutes",
+ "pr": 1217
}
- ]
+ ],
+ "timestamp": 1541740904
},
{
"version": "2.1.0",
diff --git a/packages/asset-buyer/CHANGELOG.md b/packages/asset-buyer/CHANGELOG.md
index 8845e7041..d6220767e 100644
--- a/packages/asset-buyer/CHANGELOG.md
+++ b/packages/asset-buyer/CHANGELOG.md
@@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.2.0 - _November 9, 2018_
+
+ * `getAssetBuyerForProvidedOrders` factory function now takes 3 args instead of 4 (#1187)
+ * the `OrderProvider` now requires a new method `getAvailableMakerAssetDatasAsync` and the `StandardRelayerAPIOrderProvider` requires the network id at init. (#1203)
+ * No longer require that provided orders all have the same maker and taker asset data (#1197)
+ * Fix bug where `BuyQuoteInfo` objects could return `totalEthAmount` and `feeEthAmount` that were not whole numbers (#1207)
+ * Fix bug where default values for `AssetBuyer` public facing methods could get overriden by `undefined` values (#1207)
+ * Lower default expiry buffer from 5 minutes to 2 minutes (#1217)
+
## v2.1.0 - _October 18, 2018_
* Add `gasLimit` and `gasPrice` as optional properties on `BuyQuoteExecutionOpts`
@@ -13,6 +22,7 @@ CHANGELOG
* Add `gasLimit` and `gasPrice` as optional properties on `BuyQuoteExecutionOpts` (#1116)
* Add `docs:json` command to package.json (#1139)
* Add missing types to public interface (#1139)
+ * Throw `SignatureRequestDenied` and `TransactionValueTooLow` errors when executing buy (#1147)
## v2.0.0 - _October 4, 2018_
diff --git a/packages/asset-buyer/package.json b/packages/asset-buyer/package.json
index dd0668632..fc2414952 100644
--- a/packages/asset-buyer/package.json
+++ b/packages/asset-buyer/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/asset-buyer",
- "version": "2.1.0",
+ "version": "2.2.0",
"engines": {
"node": ">=6.12"
},
@@ -36,21 +36,21 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md",
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/connect": "^3.0.2",
- "@0x/contract-wrappers": "^3.0.0",
- "@0x/json-schemas": "^2.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/subproviders": "^2.1.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
- "ethereum-types": "^1.1.1",
+ "@0x/assert": "^1.0.15",
+ "@0x/connect": "^3.0.3",
+ "@0x/contract-wrappers": "^3.0.1",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
+ "ethereum-types": "^1.1.2",
"lodash": "^4.17.10"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "^4.14.116",
"@types/mocha": "^2.2.42",
"@types/node": "*",
diff --git a/packages/asset-buyer/src/constants.ts b/packages/asset-buyer/src/constants.ts
index cc415102c..c0e1bf27d 100644
--- a/packages/asset-buyer/src/constants.ts
+++ b/packages/asset-buyer/src/constants.ts
@@ -9,7 +9,7 @@ const MAINNET_NETWORK_ID = 1;
const DEFAULT_ASSET_BUYER_OPTS: AssetBuyerOpts = {
networkId: MAINNET_NETWORK_ID,
orderRefreshIntervalMs: 10000, // 10 seconds
- expiryBufferSeconds: 300, // 5 minutes
+ expiryBufferSeconds: 120, // 2 minutes
};
const DEFAULT_BUY_QUOTE_REQUEST_OPTS: BuyQuoteRequestOpts = {
diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json
index 166c04408..f8a1051d6 100644
--- a/packages/base-contract/CHANGELOG.json
+++ b/packages/base-contract/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "3.0.3",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "3.0.2",
"changes": [
diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md
index 2981b5ef8..d544f4f99 100644
--- a/packages/base-contract/CHANGELOG.md
+++ b/packages/base-contract/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.3 - _November 9, 2018_
+
+ * Dependencies updated
+
## v3.0.2 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json
index 520dff5f9..efa4a5c81 100644
--- a/packages/base-contract/package.json
+++ b/packages/base-contract/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/base-contract",
- "version": "3.0.2",
+ "version": "3.0.3",
"engines": {
"node": ">=6.12"
},
@@ -29,7 +29,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"chai": "^4.0.1",
"make-promises-safe": "^1.1.0",
@@ -40,10 +40,10 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
- "ethereum-types": "^1.1.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
+ "ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
},
diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json
index 3412831d5..52ad9d575 100644
--- a/packages/connect/CHANGELOG.json
+++ b/packages/connect/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "3.0.3",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "3.0.2",
"changes": [
diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md
index d20b5a5f7..8e38e16de 100644
--- a/packages/connect/CHANGELOG.md
+++ b/packages/connect/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.3 - _November 9, 2018_
+
+ * Dependencies updated
+
## v3.0.2 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/connect/package.json b/packages/connect/package.json
index de846e58b..527ac5bdc 100644
--- a/packages/connect/package.json
+++ b/packages/connect/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/connect",
- "version": "3.0.2",
+ "version": "3.0.3",
"engines": {
"node": ">=6.12"
},
@@ -44,12 +44,12 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/json-schemas": "^2.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
+ "@0x/assert": "^1.0.15",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
"lodash": "^4.17.5",
"query-string": "^5.0.1",
"sinon": "^4.0.0",
@@ -57,7 +57,7 @@
"websocket": "^1.0.25"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/fetch-mock": "^6.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json
index 2727cd42b..307d73545 100644
--- a/packages/contract-addresses/CHANGELOG.json
+++ b/packages/contract-addresses/CHANGELOG.json
@@ -6,7 +6,8 @@
"pr": 1192,
"note": "Update Forwarder addresses"
}
- ]
+ ],
+ "timestamp": 1541740904
},
{
"version": "1.0.1",
diff --git a/packages/contract-addresses/CHANGELOG.md b/packages/contract-addresses/CHANGELOG.md
index 82c22f2e4..20e52cd8b 100644
--- a/packages/contract-addresses/CHANGELOG.md
+++ b/packages/contract-addresses/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.1.0 - _November 9, 2018_
+
+ * Update Forwarder addresses (#1192)
+
## v1.0.1 - _October 18, 2018_
* Initial release (#1105)
diff --git a/packages/contract-addresses/package.json b/packages/contract-addresses/package.json
index 3136d571b..47258edef 100644
--- a/packages/contract-addresses/package.json
+++ b/packages/contract-addresses/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/contract-addresses",
- "version": "1.0.1",
+ "version": "1.1.0",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json
index e6a6d02c0..8833255ed 100644
--- a/packages/contract-artifacts/CHANGELOG.json
+++ b/packages/contract-artifacts/CHANGELOG.json
@@ -6,7 +6,8 @@
"pr": 1192,
"note": "Update Forwarder artifact"
}
- ]
+ ],
+ "timestamp": 1541740904
},
{
"version": "1.0.1",
diff --git a/packages/contract-artifacts/CHANGELOG.md b/packages/contract-artifacts/CHANGELOG.md
index 82c22f2e4..b3c399985 100644
--- a/packages/contract-artifacts/CHANGELOG.md
+++ b/packages/contract-artifacts/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.1.0 - _November 9, 2018_
+
+ * Update Forwarder artifact (#1192)
+
## v1.0.1 - _October 18, 2018_
* Initial release (#1105)
diff --git a/packages/contract-artifacts/package.json b/packages/contract-artifacts/package.json
index 53f5d3c47..9c25e3ac5 100644
--- a/packages/contract-artifacts/package.json
+++ b/packages/contract-artifacts/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/contract-artifacts",
- "version": "1.0.1",
+ "version": "1.1.0",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index 9ff372e33..0ab5e5d08 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,12 +1,33 @@
[
{
+ "version": "4.0.0",
+ "changes": [
+ {
+ "note":
+ "Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync`",
+ "pr": 1235
+ },
+ {
+ "note":
+ "Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive",
+ "pr": 1235
+ },
+ {
+ "note":
+ "Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218)",
+ "pr": 1235
+ }
+ ]
+ },
+ {
"version": "3.0.1",
"changes": [
{
"note": "Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized.",
"pr": 1178
}
- ]
+ ],
+ "timestamp": 1541740904
},
{
"version": "3.0.0",
diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md
index 6f3005831..1fe903dd9 100644
--- a/packages/contract-wrappers/CHANGELOG.md
+++ b/packages/contract-wrappers/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.1 - _November 9, 2018_
+
+ * Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized. (#1178)
+
## v3.0.0 - _October 18, 2018_
* Add optional validation to the forwarder wrapper methods
@@ -15,6 +19,8 @@ CHANGELOG
* Removed `setProvider` method in top-level `ContractWrapper` class and added new `unsubscribeAll` method. (#1105)
* Some properties and methods have been renamed. For example, some methods that previously could throw no longer can, and so their names have been updated accordingly. (#1105)
* Removed ContractNotFound errors. Checking for this error was somewhat ineffecient. Relevant methods/functions now return the default error from web3-wrapper, which we feel provides enough information. (#1105)
+ * Add `ForwarderWrapperError` to public interface (#1147)
+ * Add `ContractWrapperError.SignatureRequestDenied` to public interface (#1147)
## v2.0.2 - _October 4, 2018_
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index 178675763..cb69bbd33 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/contract-wrappers",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Smart TS wrappers for 0x smart contracts",
"keywords": [
"0xproject",
@@ -37,10 +37,10 @@
"node": ">=6.0.0"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/migrations": "^2.0.0",
- "@0x/subproviders": "^2.1.0",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/migrations": "^2.0.1",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/node": "*",
@@ -65,18 +65,18 @@
"web3-provider-engine": "14.0.6"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.0.1",
- "@0x/assert": "^1.0.14",
- "@0x/contract-addresses": "^1.0.1",
- "@0x/contract-artifacts": "^1.0.1",
- "@0x/fill-scenarios": "^1.0.8",
- "@0x/json-schemas": "^2.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
- "ethereum-types": "^1.1.1",
+ "@0x/abi-gen-wrappers": "^1.0.2",
+ "@0x/assert": "^1.0.15",
+ "@0x/contract-addresses": "^1.1.0",
+ "@0x/contract-artifacts": "^1.1.0",
+ "@0x/fill-scenarios": "^1.0.9",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-blockstream": "6.0.0",
"ethereumjs-util": "^5.1.1",
"ethers": "~4.0.4",
diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
index 2e978f35b..c76e51eee 100644
--- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
@@ -18,6 +18,7 @@ import { OrderFilledCancelledFetcher } from '../fetchers/order_filled_cancelled_
import { methodOptsSchema } from '../schemas/method_opts_schema';
import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
import { txOptsSchema } from '../schemas/tx_opts_schema';
+import { validateOrderFillableOptsSchema } from '../schemas/validate_order_fillable_opts_schema';
import {
BlockRange,
EventCallback,
@@ -1114,6 +1115,9 @@ export class ExchangeWrapper extends ContractWrapper {
signedOrder: SignedOrder,
opts: ValidateOrderFillableOpts = {},
): Promise<void> {
+ assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
+ assert.doesConformToSchema('opts', opts, validateOrderFillableOptsSchema);
+
const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
this._erc20TokenWrapper,
this._erc721TokenWrapper,
@@ -1124,7 +1128,7 @@ export class ExchangeWrapper extends ContractWrapper {
const expectedFillTakerTokenAmountIfExists = opts.expectedFillTakerTokenAmount;
const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest);
- const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher);
+ const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider());
await orderValidationUtils.validateOrderFillableOrThrowAsync(
exchangeTradeSimulator,
signedOrder,
@@ -1152,7 +1156,7 @@ export class ExchangeWrapper extends ContractWrapper {
const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore);
const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest);
- const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher);
+ const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider());
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeSimulator,
this._web3Wrapper.getProvider(),
diff --git a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts
index acf7038fa..5d350916c 100644
--- a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts
+++ b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts
@@ -1,5 +1,6 @@
// tslint:disable:no-unnecessary-type-assertion
-import { AbstractOrderFilledCancelledFetcher } from '@0x/order-utils';
+import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { BlockParamLiteral } from 'ethereum-types';
@@ -18,9 +19,18 @@ export class OrderFilledCancelledFetcher implements AbstractOrderFilledCancelled
});
return filledTakerAmount;
}
- public async isOrderCancelledAsync(orderHash: string): Promise<boolean> {
+ public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> {
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const isCancelled = await this._exchange.isCancelledAsync(orderHash);
- return isCancelled;
+ const orderEpoch = await this._exchange.getOrderEpochAsync(
+ signedOrder.makerAddress,
+ signedOrder.senderAddress,
+ {
+ defaultBlock: this._stateLayer,
+ },
+ );
+ const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt;
+ return isCancelled || isCancelledByOrderEpoch;
}
public getZRXAssetData(): string {
const zrxAssetData = this._exchange.getZRXAssetData();
diff --git a/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts b/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts
new file mode 100644
index 000000000..2e111af04
--- /dev/null
+++ b/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts
@@ -0,0 +1,7 @@
+export const validateOrderFillableOptsSchema = {
+ id: '/ValidateOrderFillableOpts',
+ properties: {
+ expectedFillTakerTokenAmount: { $ref: '/wholeNumberSchema' },
+ },
+ type: 'object',
+};
diff --git a/packages/contract-wrappers/test/exchange_wrapper_test.ts b/packages/contract-wrappers/test/exchange_wrapper_test.ts
index 0e537bd83..73ce6c743 100644
--- a/packages/contract-wrappers/test/exchange_wrapper_test.ts
+++ b/packages/contract-wrappers/test/exchange_wrapper_test.ts
@@ -1,7 +1,7 @@
import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
import { FillScenarios } from '@0x/fill-scenarios';
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { DoneCallback, SignedOrder } from '@0x/types';
+import { DoneCallback, RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { BlockParamLiteral } from 'ethereum-types';
@@ -282,6 +282,19 @@ describe('ExchangeWrapper', () => {
expect(ordersInfo[1].orderHash).to.be.equal(anotherOrderHash);
});
});
+ describe('#validateOrderFillableOrThrowAsync', () => {
+ it('should throw if signature is invalid', async () => {
+ const signedOrderWithInvalidSignature = {
+ ...signedOrder,
+ signature:
+ '0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403',
+ };
+
+ expect(
+ contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrderWithInvalidSignature),
+ ).to.eventually.to.be.rejectedWith(RevertReason.InvalidOrderSignature);
+ });
+ });
describe('#isValidSignature', () => {
it('should check if the signature is valid', async () => {
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
diff --git a/packages/contracts/CHANGELOG.json b/packages/contracts/CHANGELOG.json
new file mode 100644
index 000000000..3f57a33d6
--- /dev/null
+++ b/packages/contracts/CHANGELOG.json
@@ -0,0 +1,115 @@
+[
+ {
+ "name": "Forwarder",
+ "version": "1.1.0",
+ "changes": [
+ {
+ "note": "Round up when calculating remaining amounts in marketBuy functions",
+ "pr": 1162,
+ "networks": {
+ "1": "0x5468a1dc173652ee28d249c271fa9933144746b1",
+ "3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
+ "42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Forwarder",
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "protocol v2 deploy",
+ "networks": {
+ "1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6",
+ "3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3",
+ "42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8"
+ }
+ }
+ ]
+ },
+ {
+ "name": "OrderValidator",
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "protocol v2 deploy",
+ "networks": {
+ "1": "0x9463e518dea6810309563c81d5266c1b1d149138",
+ "3": "0x90431a90516ab49af23a0530e04e8c7836e7122f",
+ "42": "0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Exchange",
+ "version": "2.0.0",
+ "changes": [
+ {
+ "note": "protocol v2 deploy",
+ "networks": {
+ "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b",
+ "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf",
+ "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2"
+ }
+ }
+ ]
+ },
+ {
+ "name": "ERC20Proxy",
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "protocol v2 deploy",
+ "networks": {
+ "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
+ "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
+ "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
+ }
+ }
+ ]
+ },
+ {
+ "name": "ERC721Proxy",
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "protocol v2 deploy",
+ "networks": {
+ "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
+ "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
+ "42": "0x2a9127c745688a165106c11cd4d647d2220af821"
+ }
+ }
+ ]
+ },
+ {
+ "name": "AssetProxyOwner",
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "protocol v2 deploy",
+ "networks": {
+ "1": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6",
+ "3": "0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b",
+ "42": "0x2c824d2882baa668e0d5202b1e7f2922278703f8"
+ }
+ }
+ ]
+ },
+ {
+ "name": "ZRXToken",
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "protocol v1 deploy",
+ "networks": {
+ "1": "0xe41d2489571d322189246dafa5ebde1f4699f498",
+ "3": "0xff67881f8d12f372d91baae9752eb3631ff0ed00",
+ "42": "0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa"
+ }
+ }
+ ]
+ }
+]
diff --git a/packages/contracts/README.md b/packages/contracts/README.md
index 5aedb249f..97a2816ff 100644
--- a/packages/contracts/README.md
+++ b/packages/contracts/README.md
@@ -1,6 +1,6 @@
## Contracts
-Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found [here](https://0xproject.com/wiki#Deployed-Addresses).
+Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [CHANGELOG](./CHANGELOG.json) of this package.
## Usage
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index 4f24310e8..bf9bb4826 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "contracts",
- "version": "2.1.50",
+ "version": "2.1.51",
"engines": {
"node": ">=6.12"
},
@@ -45,12 +45,12 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
"devDependencies": {
- "@0x/abi-gen": "^1.0.14",
- "@0x/dev-utils": "^1.0.13",
- "@0x/sol-compiler": "^1.1.8",
- "@0x/sol-cov": "^2.1.8",
- "@0x/subproviders": "^2.1.0",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/abi-gen": "^1.0.15",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/sol-compiler": "^1.1.9",
+ "@0x/sol-cov": "^2.1.9",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/tslint-config": "^1.0.10",
"@types/bn.js": "^4.11.0",
"@types/ethereumjs-abi": "^0.6.0",
"@types/lodash": "4.14.104",
@@ -71,15 +71,15 @@
"yargs": "^10.0.3"
},
"dependencies": {
- "@0x/base-contract": "^3.0.2",
- "@0x/order-utils": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1",
"ethers": "~4.0.4",
diff --git a/packages/contracts/test/utils/exchange_wrapper.ts b/packages/contracts/test/utils/exchange_wrapper.ts
index 29dba690a..c28989d3f 100644
--- a/packages/contracts/test/utils/exchange_wrapper.ts
+++ b/packages/contracts/test/utils/exchange_wrapper.ts
@@ -212,13 +212,17 @@ export class ExchangeWrapper {
return tx;
}
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
- const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex));
+ const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
return filledAmount;
}
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
return isCancelled;
}
+ public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
+ const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
+ return orderEpoch;
+ }
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo;
return orderInfo;
diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
index 81bb33318..8046771f9 100644
--- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
+++ b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
@@ -392,7 +392,7 @@ export class FillOrderCombinatorialUtils {
);
// 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected?
- const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher);
+ const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher, provider);
const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher);
const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore);
diff --git a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts b/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
index 5f5575c7b..af959e00e 100644
--- a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
+++ b/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
@@ -1,4 +1,5 @@
-import { AbstractOrderFilledCancelledFetcher } from '@0x/order-utils';
+import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { ExchangeWrapper } from './exchange_wrapper';
@@ -14,9 +15,15 @@ export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCan
const filledTakerAmount = new BigNumber(await this._exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash));
return filledTakerAmount;
}
- public async isOrderCancelledAsync(orderHash: string): Promise<boolean> {
+ public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> {
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const isCancelled = await this._exchangeWrapper.isCancelledAsync(orderHash);
- return isCancelled;
+ const orderEpoch = await this._exchangeWrapper.getOrderEpochAsync(
+ signedOrder.makerAddress,
+ signedOrder.senderAddress,
+ );
+ const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt;
+ return isCancelled || isCancelledByOrderEpoch;
}
public getZRXAssetData(): string {
return this._zrxAssetData;
diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json
index ca13c1cc8..b1b89ac99 100644
--- a/packages/dev-tools-pages/package.json
+++ b/packages/dev-tools-pages/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/dev-tools-pages",
- "version": "0.0.2",
+ "version": "0.0.3",
"engines": {
"node": ">=6.12"
},
@@ -16,7 +16,7 @@
},
"license": "Apache-2.0",
"dependencies": {
- "@0x/react-shared": "^1.0.17",
+ "@0x/react-shared": "^1.0.18",
"basscss": "^8.0.3",
"bowser": "^1.9.3",
"less": "^2.7.2",
diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json
index fd5a8d446..269cdc934 100644
--- a/packages/dev-utils/CHANGELOG.json
+++ b/packages/dev-utils/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.14",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "1.0.13",
"changes": [
{
diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md
index a6b60884e..ee614a904 100644
--- a/packages/dev-utils/CHANGELOG.md
+++ b/packages/dev-utils/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.14 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.13 - _October 18, 2018_
* Make web3-provider-engine types a 'dependency' so it's available to users of the library (#1105)
diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json
index 7c6bfde90..e1b3201d3 100644
--- a/packages/dev-utils/package.json
+++ b/packages/dev-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/dev-utils",
- "version": "1.0.13",
+ "version": "1.0.14",
"engines": {
"node": ">=6.12"
},
@@ -29,7 +29,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/dev-utils/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"make-promises-safe": "^1.1.0",
@@ -41,14 +41,14 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/subproviders": "^2.1.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/web3-provider-engine": "^14.0.0",
"chai": "^4.0.1",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"lodash": "^4.17.5"
},
"publishConfig": {
diff --git a/packages/ethereum-types/CHANGELOG.json b/packages/ethereum-types/CHANGELOG.json
index b042c4588..9db75ae9f 100644
--- a/packages/ethereum-types/CHANGELOG.json
+++ b/packages/ethereum-types/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.1.2",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "1.1.1",
"changes": [
{
diff --git a/packages/ethereum-types/CHANGELOG.md b/packages/ethereum-types/CHANGELOG.md
index 73ea54204..6ad7b4cc6 100644
--- a/packages/ethereum-types/CHANGELOG.md
+++ b/packages/ethereum-types/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.1.2 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.1.1 - _October 18, 2018_
* Add `JSONRPCResponseError` and error field on `JSONRPCResponsePayload`. (#1102)
diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json
index 49b093bdd..1630344db 100644
--- a/packages/ethereum-types/package.json
+++ b/packages/ethereum-types/package.json
@@ -1,6 +1,6 @@
{
"name": "ethereum-types",
- "version": "1.1.1",
+ "version": "1.1.2",
"engines": {
"node": ">=6.12"
},
@@ -29,7 +29,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/ethereum-types/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
"tslint": "5.11.0",
diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json
index b9840957e..8aa4e78d3 100644
--- a/packages/fill-scenarios/CHANGELOG.json
+++ b/packages/fill-scenarios/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.9",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "1.0.8",
"changes": [
{
diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md
index 20ef1322c..4ff28f82f 100644
--- a/packages/fill-scenarios/CHANGELOG.md
+++ b/packages/fill-scenarios/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.9 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.8 - _October 18, 2018_
* Updated to use new @0xproject/contract-artifacts and @0xproject/abi-gen-wrappers packages (#1105)
diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json
index ae7fa02ad..e9ca077fb 100644
--- a/packages/fill-scenarios/package.json
+++ b/packages/fill-scenarios/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/fill-scenarios",
- "version": "1.0.8",
+ "version": "1.0.9",
"description": "0x order fill scenario generator",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@@ -20,7 +20,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
@@ -28,15 +28,15 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.0.1",
- "@0x/base-contract": "^3.0.2",
- "@0x/contract-artifacts": "^1.0.1",
- "@0x/order-utils": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
- "ethereum-types": "^1.1.1",
+ "@0x/abi-gen-wrappers": "^1.0.2",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/contract-artifacts": "^1.1.0",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
+ "ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
},
diff --git a/packages/instant/.discharge.json b/packages/instant/.dogfood.discharge.json
index 9ade97d01..9ade97d01 100644
--- a/packages/instant/.discharge.json
+++ b/packages/instant/.dogfood.discharge.json
diff --git a/packages/instant/.staging.discharge.json b/packages/instant/.staging.discharge.json
new file mode 100644
index 000000000..1026b9986
--- /dev/null
+++ b/packages/instant/.staging.discharge.json
@@ -0,0 +1,13 @@
+{
+ "domain": "0x-instant-staging",
+ "build_command": "yarn build:umd:prod",
+ "upload_directory": "public",
+ "index_key": "index.html",
+ "error_key": "index.html",
+ "trailing_slashes": true,
+ "cache": 3600,
+ "aws_profile": "default",
+ "aws_region": "us-east-1",
+ "cdn": false,
+ "dns_configured": true
+}
diff --git a/packages/instant/README.md b/packages/instant/README.md
index 07b01ac95..b83a10508 100644
--- a/packages/instant/README.md
+++ b/packages/instant/README.md
@@ -53,7 +53,15 @@ You can deploy a work-in-progress version of 0x Instant at http://0x-instant-dog
To build and deploy the site run
```
-yarn deploy
+yarn deploy_dogfood
+```
+
+We also have a staging bucket that is to be updated less frequently can be used to share instant externally: http://0x-instant-staging.s3-website-us-east-1.amazonaws.com/
+
+To build and deploy to this bucket, run
+
+```
+yarn deploy_staging
```
**NOTE: On deploying the site, it will say the site is available at a non-existent URL. Please ignore and use the (now updated) URL above.**
diff --git a/packages/instant/package.json b/packages/instant/package.json
index 81d2e4c7b..3c87743c1 100644
--- a/packages/instant/package.json
+++ b/packages/instant/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/instant",
- "version": "0.0.3",
+ "version": "0.0.4",
"engines": {
"node": ">=6.12"
},
@@ -22,7 +22,8 @@
"rebuild_and_test": "run-s clean build test",
"test:circleci": "yarn test:coverage",
"clean": "shx rm -rf lib coverage scripts",
- "deploy": "discharge deploy",
+ "deploy_dogfood": "discharge deploy -c .dogfood.discharge.json",
+ "deploy_staging": "discharge deploy -c .staging.discharge.json",
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
},
"config": {
@@ -44,15 +45,17 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/asset-buyer": "^2.1.0",
- "@0x/json-schemas": "^2.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
- "ethereum-types": "^1.1.1",
+ "@0x/assert": "^1.0.15",
+ "@0x/asset-buyer": "^2.2.0",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
+ "copy-to-clipboard": "^3.0.8",
+ "ethereum-types": "^1.1.2",
"lodash": "^4.17.10",
"polished": "^2.2.0",
"react": "^16.5.2",
@@ -64,8 +67,8 @@
"ts-optchain": "^0.1.1"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
- "@static/discharge": "^1.2.2",
+ "@0x/tslint-config": "^1.0.10",
+ "@static/discharge": "https://github.com/0xProject/discharge.git",
"@types/enzyme": "^3.1.14",
"@types/enzyme-adapter-react-16": "^1.0.3",
"@types/jest": "^23.3.5",
diff --git a/packages/instant/public/external.css b/packages/instant/public/external.css
new file mode 100644
index 000000000..cab11112a
--- /dev/null
+++ b/packages/instant/public/external.css
@@ -0,0 +1,25 @@
+/*
+ CSS file meant to represent an external (integrators) stylesheet and
+ help ensure that instant looks consistent across environments.
+*/
+
+button {
+ font-size: 50px;
+ height: 200px;
+ background-color: red;
+}
+
+input {
+ padding: 100px;
+ font-size: 50px;
+ height: 100px;
+}
+
+div {
+ padding: 3px;
+}
+
+p {
+ background-color: green;
+ margin: 10px;
+}
diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html
index 92c8a6c21..f6c809e33 100644
--- a/packages/instant/public/index.html
+++ b/packages/instant/public/index.html
@@ -5,6 +5,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>0x Instant Dev Environment</title>
+ <link rel="stylesheet" href="/external.css">
<script type="text/javascript" src="/main.bundle.js" charset="utf-8"></script>
<script type="text/javascript" src="https://unpkg.com/jsuri@1.3.1/Uri.js" charset="utf-8"></script>
<script type="text/javascript" src="https://unpkg.com/bignumber.js@4.1.0/bignumber.js" charset="utf-8"></script>
@@ -42,14 +43,14 @@
takerAddress: '0x0000000000000000000000000000000000000000',
makerFee: new BigNumber('0'),
takerFee: new BigNumber('0'),
- makerAssetAmount: new BigNumber('400000000000000000000'),
- takerAssetAmount: new BigNumber('40000000000000000000'),
+ makerAssetAmount: new BigNumber('200000000000000000000'),
+ takerAssetAmount: new BigNumber('10000000000000000000'),
makerAssetData: '0xf47261b00000000000000000000000008cb3971b8eb709c14616bd556ff6683019e90d9c',
takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
- expirationTimeSeconds: new BigNumber('1543046400'),
+ expirationTimeSeconds: new BigNumber('1601535600'),
feeRecipientAddress: '0x0000000000000000000000000000000000000000',
- salt: new BigNumber('47929252863126413473766089649682650973189811771354566206928245255479607883031'),
- signature: '0x1c0bf8ba709ceb5b32e6b0b5a8bb7f07e9d19aba88d8530715f8a298d12188e3862fcc0a30ddfad4062b30459f2859323c064052f12cc687466c457934b9419a1b03',
+ salt: new BigNumber('3101985707338942582579795423923841749956600670712030922928319824580764688653'),
+ signature: '0x1bd4d5686fea801fe33c68c4944356085e7e6cb553eb7073160abd815609f714e85fb47f44b7ffd0a2a1321ac40d72d55163869d0a50fdb5a402132150fe33a08403',
exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2'
},
// Order selling ZRX
@@ -68,6 +69,40 @@
salt: new BigNumber('64592004666704945574675477805199411288137454783320798602050822322450089238268'),
signature: '0x1c13cacddca8d7d8248e91f412377e68f8f1f9891a59a6c1b2eea9f7b33558c30c4fb86a448e08ab7def40a28fb3a3062dcb33bb3c45302447fce5c4288b7c7f5b03',
exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2'
+ },
+ // Order selling GNT
+ {
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e',
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ makerFee: new BigNumber('0'),
+ takerFee: new BigNumber('0'),
+ makerAssetAmount: new BigNumber('250000000000000000000'),
+ takerAssetAmount: new BigNumber('10000000000000000000'),
+ makerAssetData: '0xf47261b000000000000000000000000031fb614e223706f15d0d3c5f4b08bdf0d5c78623',
+ takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
+ expirationTimeSeconds: new BigNumber('1601535600'),
+ feeRecipientAddress: '0x0000000000000000000000000000000000000000',
+ salt: new BigNumber('40204378562212615907903051460421336779451270522691667164301816101569427926606'),
+ signature: '0x1c788bf4b93769da1e8f195f52f0f59b4a298ac6da30cf6d05a87ed4be5ee974f61352ed1bc6a0844d0962b8c894c9ca08e452431255958a4e98dd93cbe1fbc73803',
+ exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2'
+ },
+ // Order selling MKR
+ {
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e',
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ makerFee: new BigNumber('0'),
+ takerFee: new BigNumber('0'),
+ makerAssetAmount: new BigNumber('200000000000000000000'),
+ takerAssetAmount: new BigNumber('5000000000000000000'),
+ makerAssetData: '0xf47261b00000000000000000000000007b6b10caa9e8e9552ba72638ea5b47c25afea1f3',
+ takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
+ expirationTimeSeconds: new BigNumber('1601535600'),
+ feeRecipientAddress: '0x0000000000000000000000000000000000000000',
+ salt: new BigNumber('71338269924068280039932133924198049371838034090153601678083172009862985793828'),
+ signature: '0x1bb3151d57ee1e8fa697767ce83ee4ba77d1ceb8cc1e79c7d77126b3687517704c50c6b3d9cb42c7e7d4478d574b297dfbd1626c5c18a7bc9c2a792c4c07f0797c03',
+ exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2'
}
];
const queryParams = new Uri(window.location.search);
@@ -87,7 +122,7 @@
};
}
const renderOptionsOverrides = {
- orderSource: orderSourceOverride === 'provided' ? [providedOrder] : orderSourceOverride,
+ orderSource: orderSourceOverride === 'provided' ? providedOrders : orderSourceOverride,
networkId: +queryParams.getQueryParamValue('networkId') || undefined,
defaultAssetBuyAmount: +queryParams.getQueryParamValue('defaultAssetBuyAmount') || undefined,
availableAssetDatas: availableAssetDatasString ? JSON.parse(availableAssetDatasString) : undefined,
diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx
index 6ef8f0ac3..29ce8fafb 100644
--- a/packages/instant/src/components/amount_placeholder.tsx
+++ b/packages/instant/src/components/amount_placeholder.tsx
@@ -4,7 +4,7 @@ import { ColorOption } from '../style/theme';
import { Pulse } from './animations/pulse';
-import { Text } from './ui';
+import { Text } from './ui/text';
interface PlainPlaceholder {
color: ColorOption;
diff --git a/packages/instant/src/components/animations/position_animation.tsx b/packages/instant/src/components/animations/position_animation.tsx
index 4bb21befb..8b3b294b7 100644
--- a/packages/instant/src/components/animations/position_animation.tsx
+++ b/packages/instant/src/components/animations/position_animation.tsx
@@ -1,5 +1,6 @@
-import { Keyframes } from 'styled-components';
+import { InterpolationValue } from 'styled-components';
+import { media, OptionallyScreenSpecific, stylesForMedia } from '../../style/media';
import { css, keyframes, styled } from '../../style/theme';
export interface TransitionInfo {
@@ -51,30 +52,59 @@ export interface PositionAnimationSettings {
right?: TransitionInfo;
timingFunction: string;
duration?: string;
+ position?: string;
}
-export interface PositionAnimationProps extends PositionAnimationSettings {
- position: string;
+const generatePositionAnimationCss = (positionSettings: PositionAnimationSettings) => {
+ return css`
+ animation-name: ${slideKeyframeGenerator(
+ positionSettings.position || 'relative',
+ positionSettings.top,
+ positionSettings.bottom,
+ positionSettings.left,
+ positionSettings.right,
+ )};
+ animation-duration: ${positionSettings.duration || '0.3s'};
+ animation-timing-function: ${positionSettings.timingFunction};
+ animation-delay: 0s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ position: ${positionSettings.position || 'relative'};
+ width: 100%;
+ `;
+};
+
+export interface PositionAnimationProps {
+ positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
+ zIndex?: OptionallyScreenSpecific<number>;
+ height?: string;
}
+const defaultAnimation = (positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>) => {
+ const bestDefault = 'default' in positionSettings ? positionSettings.default : positionSettings;
+ return generatePositionAnimationCss(bestDefault);
+};
+const animationForSize = (
+ positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>,
+ sizeKey: 'sm' | 'md' | 'lg',
+ mediaFn: (...args: any[]) => InterpolationValue[],
+) => {
+ // checking default makes sure we have a PositionAnimationSettings object
+ // and then we check to see if we have a setting for the specific `sizeKey`
+ const animationSettingsForSize = 'default' in positionSettings && positionSettings[sizeKey];
+ return animationSettingsForSize && mediaFn`${generatePositionAnimationCss(animationSettingsForSize)}`;
+};
+
export const PositionAnimation =
styled.div <
PositionAnimationProps >
`
- animation-name: ${props =>
- css`
- ${slideKeyframeGenerator(props.position, props.top, props.bottom, props.left, props.right)};
- `};
- animation-duration: ${props => props.duration || '0.3s'};
- animation-timing-function: ${props => props.timingFunction};
- animation-delay: 0s;
- animation-iteration-count: 1;
- animation-fill-mode: forwards;
- position: ${props => props.position};
- height: 100%;
- width: 100%;
+ && {
+ ${props => props.zIndex && stylesForMedia<number>('z-index', props.zIndex)}
+ ${props => defaultAnimation(props.positionSettings)}
+ ${props => animationForSize(props.positionSettings, 'sm', media.small)}
+ ${props => animationForSize(props.positionSettings, 'md', media.medium)}
+ ${props => animationForSize(props.positionSettings, 'lg', media.large)}
+ ${props => (props.height ? `height: ${props.height};` : '')}
+ }
`;
-
-PositionAnimation.defaultProps = {
- position: 'relative',
-};
diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx
index 66a314c7f..9adb1c674 100644
--- a/packages/instant/src/components/animations/slide_animation.tsx
+++ b/packages/instant/src/components/animations/slide_animation.tsx
@@ -1,22 +1,25 @@
import * as React from 'react';
+import { OptionallyScreenSpecific } from '../../style/media';
+
import { PositionAnimation, PositionAnimationSettings } from './position_animation';
export type SlideAnimationState = 'slidIn' | 'slidOut' | 'none';
export interface SlideAnimationProps {
- position: string;
animationState: SlideAnimationState;
- slideInSettings: PositionAnimationSettings;
- slideOutSettings: PositionAnimationSettings;
+ slideInSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
+ slideOutSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
+ zIndex?: OptionallyScreenSpecific<number>;
+ height?: string;
}
export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = props => {
if (props.animationState === 'none') {
return <React.Fragment>{props.children}</React.Fragment>;
}
- const propsToUse = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;
+ const positionSettings = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;
return (
- <PositionAnimation position={props.position} {...propsToUse}>
+ <PositionAnimation height={props.height} positionSettings={positionSettings} zIndex={props.zIndex}>
{props.children}
</PositionAnimation>
);
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 9d9a8540c..877ab275c 100644
--- a/packages/instant/src/components/buy_button.tsx
+++ b/packages/instant/src/components/buy_button.tsx
@@ -1,4 +1,5 @@
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import * as React from 'react';
@@ -7,16 +8,17 @@ import { oc } from 'ts-optchain';
import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
import { ColorOption } from '../style/theme';
import { AffiliateInfo, ZeroExInstantError } from '../types';
-import { getBestAddress } from '../util/address';
-import { balanceUtil } from '../util/balance';
import { gasPriceEstimator } from '../util/gas_price_estimator';
import { util } from '../util/util';
-import { Button, Text } from './ui';
+import { Button } from './ui/button';
export interface BuyButtonProps {
+ accountAddress?: string;
+ accountEthBalanceInWei?: BigNumber;
buyQuote?: BuyQuote;
- assetBuyer?: AssetBuyer;
+ assetBuyer: AssetBuyer;
+ web3Wrapper: Web3Wrapper;
affiliateInfo?: AffiliateInfo;
onValidationPending: (buyQuote: BuyQuote) => void;
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
@@ -33,39 +35,41 @@ export class BuyButton extends React.Component<BuyButtonProps> {
onBuyFailure: util.boundNoop,
};
public render(): React.ReactNode {
- const shouldDisableButton = _.isUndefined(this.props.buyQuote) || _.isUndefined(this.props.assetBuyer);
+ const { buyQuote, accountAddress } = this.props;
+ const shouldDisableButton = _.isUndefined(buyQuote) || _.isUndefined(accountAddress);
return (
- <Button width="100%" onClick={this._handleClick} isDisabled={shouldDisableButton}>
- <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
- Buy
- </Text>
+ <Button
+ width="100%"
+ onClick={this._handleClick}
+ isDisabled={shouldDisableButton}
+ fontColor={ColorOption.white}
+ fontSize="20px"
+ >
+ Buy
</Button>
);
}
private readonly _handleClick = async () => {
// The button is disabled when there is no buy quote anyway.
- const { buyQuote, assetBuyer, affiliateInfo } = this.props;
- if (_.isUndefined(buyQuote) || _.isUndefined(assetBuyer)) {
+ const { buyQuote, assetBuyer, affiliateInfo, accountAddress, accountEthBalanceInWei, web3Wrapper } = this.props;
+ if (_.isUndefined(buyQuote) || _.isUndefined(accountAddress)) {
return;
}
-
this.props.onValidationPending(buyQuote);
- const web3Wrapper = new Web3Wrapper(assetBuyer.provider);
- const takerAddress = await getBestAddress(web3Wrapper);
-
- const hasSufficientEth = await balanceUtil.hasSufficientEth(takerAddress, buyQuote, web3Wrapper);
+ const ethNeededForBuy = buyQuote.worstCaseQuoteInfo.totalEthAmount;
+ // if we don't have a balance for the user, let the transaction through, it will be handled by the wallet
+ const hasSufficientEth = _.isUndefined(accountEthBalanceInWei) || accountEthBalanceInWei.gte(ethNeededForBuy);
if (!hasSufficientEth) {
this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH);
return;
}
-
let txHash: string | undefined;
const gasInfo = await gasPriceEstimator.getGasInfoAsync();
const feeRecipient = oc(affiliateInfo).feeRecipient();
try {
txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, {
feeRecipient,
- takerAddress,
+ takerAddress: accountAddress,
gasPrice: gasInfo.gasPriceInWei,
});
} catch (e) {
@@ -80,7 +84,6 @@ export class BuyButton extends React.Component<BuyButtonProps> {
}
throw e;
}
-
const startTimeUnix = new Date().getTime();
const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs;
this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
@@ -93,7 +96,6 @@ export class BuyButton extends React.Component<BuyButtonProps> {
}
throw e;
}
-
this.props.onBuySuccess(buyQuote, txHash);
};
}
diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx
index e259e5606..bc7319423 100644
--- a/packages/instant/src/components/buy_order_progress.tsx
+++ b/packages/instant/src/components/buy_order_progress.tsx
@@ -3,7 +3,7 @@ import * as React from 'react';
import { TimedProgressBar } from '../components/timed_progress_bar';
import { TimeCounter } from '../components/time_counter';
-import { Container } from '../components/ui';
+import { Container } from '../components/ui/container';
import { OrderProcessState, OrderState } from '../types';
export interface BuyOrderProgressProps {
@@ -14,12 +14,12 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> =
const { buyOrderState } = props;
if (
- buyOrderState.processState === OrderProcessState.PROCESSING ||
- buyOrderState.processState === OrderProcessState.SUCCESS ||
- buyOrderState.processState === OrderProcessState.FAILURE
+ buyOrderState.processState === OrderProcessState.Processing ||
+ buyOrderState.processState === OrderProcessState.Success ||
+ buyOrderState.processState === OrderProcessState.Failure
) {
const progress = buyOrderState.progress;
- const hasEnded = buyOrderState.processState !== OrderProcessState.PROCESSING;
+ const hasEnded = buyOrderState.processState !== OrderProcessState.Processing;
const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix;
return (
<Container padding="20px 20px 0px 20px" width="100%">
diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx
index 5c074a67a..6041bf4f5 100644
--- a/packages/instant/src/components/buy_order_state_buttons.tsx
+++ b/packages/instant/src/components/buy_order_state_buttons.tsx
@@ -1,4 +1,6 @@
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import * as React from 'react';
import { ColorOption } from '../style/theme';
@@ -7,12 +9,17 @@ import { AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
import { BuyButton } from './buy_button';
import { PlacingOrderButton } from './placing_order_button';
import { SecondaryButton } from './secondary_button';
-import { Button, Flex, Text } from './ui';
+
+import { Button } from './ui/button';
+import { Flex } from './ui/flex';
export interface BuyOrderStateButtonProps {
+ accountAddress?: string;
+ accountEthBalanceInWei?: BigNumber;
buyQuote?: BuyQuote;
buyOrderProcessingState: OrderProcessState;
- assetBuyer?: AssetBuyer;
+ assetBuyer: AssetBuyer;
+ web3Wrapper: Web3Wrapper;
affiliateInfo?: AffiliateInfo;
onViewTransaction: () => void;
onValidationPending: (buyQuote: BuyQuote) => void;
@@ -25,13 +32,11 @@ export interface BuyOrderStateButtonProps {
}
export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonProps> = props => {
- if (props.buyOrderProcessingState === OrderProcessState.FAILURE) {
+ 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 width="48%" onClick={props.onRetry} fontColor={ColorOption.white} fontSize="16px">
+ Back
</Button>
<SecondaryButton width="48%" onClick={props.onViewTransaction}>
Details
@@ -39,18 +44,21 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
</Flex>
);
} else if (
- props.buyOrderProcessingState === OrderProcessState.SUCCESS ||
- props.buyOrderProcessingState === OrderProcessState.PROCESSING
+ props.buyOrderProcessingState === OrderProcessState.Success ||
+ props.buyOrderProcessingState === OrderProcessState.Processing
) {
return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>;
- } else if (props.buyOrderProcessingState === OrderProcessState.VALIDATING) {
+ } else if (props.buyOrderProcessingState === OrderProcessState.Validating) {
return <PlacingOrderButton />;
}
return (
<BuyButton
+ accountAddress={props.accountAddress}
+ accountEthBalanceInWei={props.accountEthBalanceInWei}
buyQuote={props.buyQuote}
assetBuyer={props.assetBuyer}
+ web3Wrapper={props.web3Wrapper}
affiliateInfo={props.affiliateInfo}
onValidationPending={props.onValidationPending}
onValidationFail={props.onValidationFail}
diff --git a/packages/instant/src/components/css_reset.tsx b/packages/instant/src/components/css_reset.tsx
new file mode 100644
index 000000000..0bef85389
--- /dev/null
+++ b/packages/instant/src/components/css_reset.tsx
@@ -0,0 +1,32 @@
+import { INJECTED_DIV_CLASS } from '../constants';
+import { createGlobalStyle } from '../style/theme';
+
+export interface CSSResetProps {}
+
+/*
+* Derived from
+* https://github.com/jtrost/Complete-CSS-Reset
+*/
+export const CSSReset = createGlobalStyle`
+ .${INJECTED_DIV_CLASS} {
+ a, abbr, area, article, aside, audio, b, bdo, blockquote, body, button,
+ canvas, caption, cite, code, col, colgroup, command, datalist, dd, del,
+ details, dialog, dfn, div, dl, dt, em, embed, fieldset, figure, form,
+ h1, h2, h3, h4, h5, h6, head, header, hgroup, hr, html, i, iframe, img,
+ input, ins, keygen, kbd, label, legend, li, map, mark, menu, meter, nav,
+ noscript, object, ol, optgroup, option, output, p, param, pre, progress,
+ q, rp, rt, ruby, samp, section, select, small, span, strong, sub, sup,
+ table, tbody, td, textarea, tfoot, th, thead, time, tr, ul, var, video {
+ background: transparent;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ margin: 0;
+ outline: none;
+ padding: 0;
+ text-align: left;
+ text-decoration: none;
+ vertical-align: baseline;
+ }
+ }
+`;
diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx
index 6ad0e92e7..520ac33d5 100644
--- a/packages/instant/src/components/erc20_asset_amount_input.tsx
+++ b/packages/instant/src/components/erc20_asset_amount_input.tsx
@@ -8,7 +8,11 @@ import { assetUtils } from '../util/asset';
import { util } from '../util/util';
import { ScalingAmountInput } from './scaling_amount_input';
-import { Container, Flex, Icon, Text } from './ui';
+
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Icon } from './ui/icon';
+import { Text } from './ui/text';
// Asset amounts only apply to ERC20 assets
export interface ERC20AssetAmountInputProps {
@@ -109,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
}
return (
<Container marginLeft="5px">
- <Icon icon="chevron" width={12} onClick={this._handleSelectAssetClick} />
+ <Icon icon="chevron" width={12} stroke={ColorOption.white} onClick={this._handleSelectAssetClick} />
</Container>
);
};
diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
index 481778495..3503ff31a 100644
--- a/packages/instant/src/components/erc20_token_selector.tsx
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -6,7 +6,11 @@ import { ERC20Asset } from '../types';
import { assetUtils } from '../util/asset';
import { SearchInput } from './search_input';
-import { Circle, Container, Flex, Text } from './ui';
+
+import { Circle } from './ui/circle';
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Text } from './ui/text';
export interface ERC20TokenSelectorProps {
tokens: ERC20Asset[];
@@ -24,14 +28,14 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
public render(): React.ReactNode {
const { tokens, onTokenSelect } = this.props;
return (
- <Container>
+ <Container height="100%">
<SearchInput
placeholder="Search tokens..."
width="100%"
value={this.state.searchQuery}
onChange={this._handleSearchInputChange}
/>
- <Container overflow="scroll" height="275px" marginTop="10px">
+ <Container overflow="scroll" height="calc(100% - 80px)" marginTop="10px">
{_.map(tokens, token => {
if (!this._isTokenQueryMatch(token)) {
return null;
@@ -81,7 +85,7 @@ class TokenSelectorRow extends React.Component<TokenSelectorRowProps> {
<Container marginLeft="5px">
<Flex justify="flex-start">
<Container marginRight="10px">
- <Circle diameter={30} fillColor={token.metaData.primaryColor}>
+ <Circle diameter={30} rawColor={token.metaData.primaryColor}>
<Flex height="100%">
<Text fontColor={ColorOption.white} fontSize="8px">
{displaySymbol}
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 80d7a3ee2..b07776b2c 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -8,7 +8,11 @@ import { AsyncProcessState, ERC20Asset, OrderProcessState, OrderState } from '..
import { format } from '../util/format';
import { AmountPlaceholder } from './amount_placeholder';
-import { Container, Flex, Icon, Spinner, Text } from './ui';
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Icon } from './ui/icon';
+import { Spinner } from './ui/spinner';
+import { Text } from './ui/text';
export interface InstantHeadingProps {
selectedAssetAmount?: BigNumber;
@@ -73,11 +77,11 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
private _renderIcon(): React.ReactNode {
const processState = this.props.buyOrderState.processState;
- if (processState === OrderProcessState.FAILURE) {
+ if (processState === OrderProcessState.Failure) {
return <Icon icon="failed" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
- } else if (processState === OrderProcessState.PROCESSING) {
+ } else if (processState === OrderProcessState.Processing) {
return <Spinner widthPx={ICON_HEIGHT} heightPx={ICON_HEIGHT} />;
- } else if (processState === OrderProcessState.SUCCESS) {
+ } else if (processState === OrderProcessState.Success) {
return <Icon icon="success" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
}
return undefined;
@@ -85,11 +89,11 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
private _renderTopText(): React.ReactNode {
const processState = this.props.buyOrderState.processState;
- if (processState === OrderProcessState.FAILURE) {
+ if (processState === OrderProcessState.Failure) {
return 'Order failed';
- } else if (processState === OrderProcessState.PROCESSING) {
+ } else if (processState === OrderProcessState.Processing) {
return 'Processing Order...';
- } else if (processState === OrderProcessState.SUCCESS) {
+ } else if (processState === OrderProcessState.Success) {
return 'Tokens received!';
}
@@ -97,7 +101,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
}
private _renderPlaceholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode {
- if (this.props.quoteRequestState === AsyncProcessState.PENDING) {
+ if (this.props.quoteRequestState === AsyncProcessState.Pending) {
return <AmountPlaceholder isPulsating={true} color={PLACEHOLDER_COLOR} />;
}
if (_.isUndefined(this.props.selectedAssetAmount)) {
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index 704009d89..9abd7137e 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -8,7 +8,10 @@ import { ColorOption } from '../style/theme';
import { format } from '../util/format';
import { AmountPlaceholder } from './amount_placeholder';
-import { Container, Flex, Text } from './ui';
+
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Text } from './ui/text';
export interface OrderDetailsProps {
buyQuoteInfo?: BuyQuoteInfo;
@@ -23,7 +26,7 @@ export class OrderDetails extends React.Component<OrderDetailsProps> {
const ethTokenFee = buyQuoteAccessor.feeEthAmount();
const totalEthAmount = buyQuoteAccessor.totalEthAmount();
return (
- <Container padding="20px" width="100%">
+ <Container padding="20px" width="100%" flexGrow={1}>
<Container marginBottom="10px">
<Text
letterSpacing="1px"
diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx
new file mode 100644
index 000000000..8c0b47d72
--- /dev/null
+++ b/packages/instant/src/components/payment_method.tsx
@@ -0,0 +1,45 @@
+import { BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { ColorOption } from '../style/theme';
+import { Network } from '../types';
+
+import { PaymentMethodDropdown } from './payment_method_dropdown';
+import { Circle } from './ui/circle';
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Text } from './ui/text';
+
+export interface PaymentMethodProps {}
+
+export const PaymentMethod: React.StatelessComponent<PaymentMethodProps> = () => (
+ <Container padding="20px" width="100%">
+ <Container marginBottom="10px">
+ <Flex justify="space-between">
+ <Text
+ letterSpacing="1px"
+ fontColor={ColorOption.primaryColor}
+ fontWeight={600}
+ textTransform="uppercase"
+ fontSize="14px"
+ >
+ Payment Method
+ </Text>
+ <Flex>
+ <Circle color={ColorOption.green} diameter={8} />
+ <Container marginLeft="3px">
+ <Text fontColor={ColorOption.darkGrey} fontSize="12px">
+ MetaMask
+ </Text>
+ </Container>
+ </Flex>
+ </Flex>
+ </Container>
+ <PaymentMethodDropdown
+ accountAddress="0xa1b2c3d4e5f6g7h8j9k10"
+ accountEthBalanceInWei={new BigNumber(10500000000000000000)}
+ network={Network.Mainnet}
+ />
+ </Container>
+);
diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx
new file mode 100644
index 000000000..bdce2a49d
--- /dev/null
+++ b/packages/instant/src/components/payment_method_dropdown.tsx
@@ -0,0 +1,44 @@
+import { BigNumber } from '@0x/utils';
+import copy from 'copy-to-clipboard';
+import * as React from 'react';
+
+import { Network } from '../types';
+import { etherscanUtil } from '../util/etherscan';
+import { format } from '../util/format';
+
+import { Dropdown, DropdownItemConfig } from './ui/dropdown';
+
+export interface PaymentMethodDropdownProps {
+ accountAddress: string;
+ accountEthBalanceInWei?: BigNumber;
+ network: Network;
+}
+
+export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdownProps> {
+ public render(): React.ReactNode {
+ const { accountAddress, accountEthBalanceInWei } = this.props;
+ const value = format.ethAddress(accountAddress);
+ const label = format.ethBaseAmount(accountEthBalanceInWei, 4, '') as string;
+ return <Dropdown value={value} label={label} items={this._getDropdownItemConfigs()} />;
+ }
+ private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => {
+ const viewOnEtherscan = {
+ text: 'View on Etherscan',
+ onClick: this._handleEtherscanClick,
+ };
+ const copyAddressToClipboard = {
+ text: 'Copy address to clipboard',
+ onClick: this._handleCopyToClipboardClick,
+ };
+ return [viewOnEtherscan, copyAddressToClipboard];
+ };
+ private readonly _handleEtherscanClick = (): void => {
+ const { accountAddress, network } = this.props;
+ const etherscanUrl = etherscanUtil.getEtherScanEthAddressIfExists(accountAddress, network);
+ window.open(etherscanUrl, '_blank');
+ };
+ private readonly _handleCopyToClipboardClick = (): void => {
+ const { accountAddress } = this.props;
+ copy(accountAddress);
+ };
+}
diff --git a/packages/instant/src/components/placing_order_button.tsx b/packages/instant/src/components/placing_order_button.tsx
index e5a6371e6..d774d7d27 100644
--- a/packages/instant/src/components/placing_order_button.tsx
+++ b/packages/instant/src/components/placing_order_button.tsx
@@ -2,15 +2,15 @@ import * as React from 'react';
import { ColorOption } from '../style/theme';
-import { Button, Container, Spinner, Text } from './ui';
+import { Button } from './ui/button';
+import { Container } from './ui/container';
+import { Spinner } from './ui/spinner';
export const PlacingOrderButton: React.StatelessComponent<{}> = props => (
- <Button isDisabled={true} width="100%">
+ <Button isDisabled={true} width="100%" fontColor={ColorOption.white} fontSize="20px">
<Container display="inline-block" position="relative" top="3px" marginRight="8px">
<Spinner widthPx={20} heightPx={20} />
</Container>
- <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
- Placing Order&hellip;
- </Text>
+ Placing Order&hellip;
</Button>
);
diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 11748b729..1abadb78b 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
import { ColorOption } from '../style/theme';
import { util } from '../util/util';
-import { Input } from './ui';
+import { Input } from './ui/input';
export enum ScalingInputPhase {
FixedFontSize,
diff --git a/packages/instant/src/components/search_input.tsx b/packages/instant/src/components/search_input.tsx
index f082eaa16..3a693b9f8 100644
--- a/packages/instant/src/components/search_input.tsx
+++ b/packages/instant/src/components/search_input.tsx
@@ -3,7 +3,10 @@ import * as React from 'react';
import { ColorOption } from '../style/theme';
-import { Container, Flex, Icon, Input, InputProps } from './ui';
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Icon } from './ui/icon';
+import { Input, InputProps } from './ui/input';
export interface SearchInputProps extends InputProps {
backgroundColor?: ColorOption;
diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx
index ca698c77a..df0539606 100644
--- a/packages/instant/src/components/secondary_button.tsx
+++ b/packages/instant/src/components/secondary_button.tsx
@@ -3,7 +3,7 @@ import * as React from 'react';
import { ColorOption } from '../style/theme';
-import { Button, ButtonProps, Text } from './ui';
+import { Button, ButtonProps } from './ui/button';
export interface SecondaryButtonProps extends ButtonProps {}
@@ -15,11 +15,11 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p
borderColor={ColorOption.lightGrey}
width={props.width}
onClick={props.onClick}
+ fontColor={ColorOption.primaryColor}
+ fontSize="16px"
{...buttonProps}
>
- <Text fontColor={ColorOption.primaryColor} fontWeight={600} fontSize="16px">
- {props.children}
- </Text>
+ {props.children}
</Button>
);
};
diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx
index 17643fd7d..a8d4e391c 100644
--- a/packages/instant/src/components/sliding_error.tsx
+++ b/packages/instant/src/components/sliding_error.tsx
@@ -1,11 +1,15 @@
import * as React from 'react';
+import { ScreenSpecification } from '../style/media';
import { ColorOption } from '../style/theme';
+import { zIndex } from '../style/z_index';
import { PositionAnimationSettings } from './animations/position_animation';
import { SlideAnimation, SlideAnimationState } from './animations/slide_animation';
-import { Container, Flex, Text } from './ui';
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Text } from './ui/text';
export interface ErrorProps {
icon: string;
@@ -19,6 +23,7 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
backgroundColor={ColorOption.lightOrange}
width="100%"
borderRadius="6px"
+ marginTop="10px"
marginBottom="10px"
>
<Flex justify="flex-start">
@@ -37,25 +42,51 @@ export interface SlidingErrorProps extends ErrorProps {
}
export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props => {
const slideAmount = '120px';
- const slideUpSettings: PositionAnimationSettings = {
+
+ const desktopSlideIn: PositionAnimationSettings = {
timingFunction: 'ease-in',
top: {
from: slideAmount,
to: '0px',
},
+ position: 'relative',
};
- const slideDownSettings: PositionAnimationSettings = {
+ const desktopSlideOut: PositionAnimationSettings = {
timingFunction: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
top: {
from: '0px',
to: slideAmount,
},
+ position: 'relative',
+ };
+
+ const mobileSlideIn: PositionAnimationSettings = {
+ duration: '0.5s',
+ timingFunction: 'ease-in',
+ top: { from: '-120px', to: '0px' },
+ position: 'fixed',
+ };
+ const moblieSlideOut: PositionAnimationSettings = {
+ duration: '0.5s',
+ timingFunction: 'ease-in',
+ top: { from: '0px', to: '-120px' },
+ position: 'fixed',
+ };
+
+ const slideUpSettings: ScreenSpecification<PositionAnimationSettings> = {
+ default: desktopSlideIn,
+ sm: mobileSlideIn,
};
+ const slideOutSettings: ScreenSpecification<PositionAnimationSettings> = {
+ default: desktopSlideOut,
+ sm: moblieSlideOut,
+ };
+
return (
<SlideAnimation
- position="relative"
slideInSettings={slideUpSettings}
- slideOutSettings={slideDownSettings}
+ slideOutSettings={slideOutSettings}
+ zIndex={{ sm: zIndex.errorPopup, default: zIndex.errorPopBehind }}
animationState={props.animationState}
>
<Error icon={props.icon} message={props.message} />
diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx
index ea1d6b9a1..9d16f9560 100644
--- a/packages/instant/src/components/sliding_panel.tsx
+++ b/packages/instant/src/components/sliding_panel.tsx
@@ -5,7 +5,11 @@ import { zIndex } from '../style/z_index';
import { PositionAnimationSettings } from './animations/position_animation';
import { SlideAnimation, SlideAnimationState } from './animations/slide_animation';
-import { Container, Flex, Icon, Text } from './ui';
+
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Icon } from './ui/icon';
+import { Text } from './ui/text';
export interface PanelProps {
title?: string;
@@ -26,7 +30,9 @@ export const Panel: React.StatelessComponent<PanelProps> = ({ title, children, o
<Icon width={12} color={ColorOption.lightGrey} icon="closeX" onClick={onClose} />
</Container>
</Flex>
- <Container marginTop="10px">{children}</Container>
+ <Container marginTop="10px" height="100%">
+ {children}
+ </Container>
</Container>
);
@@ -47,6 +53,7 @@ export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props =
from: slideAmount,
to: '0px',
},
+ position: 'absolute',
};
const slideDownSettings: PositionAnimationSettings = {
duration: '0.3s',
@@ -55,13 +62,14 @@ export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props =
from: '0px',
to: slideAmount,
},
+ position: 'absolute',
};
return (
<SlideAnimation
- position="absolute"
slideInSettings={slideUpSettings}
slideOutSettings={slideDownSettings}
animationState={animationState}
+ height="100%"
>
<Panel {...rest} />
</SlideAnimation>
diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx
index f2a6f5745..59aaa33a1 100644
--- a/packages/instant/src/components/timed_progress_bar.tsx
+++ b/packages/instant/src/components/timed_progress_bar.tsx
@@ -70,9 +70,11 @@ export const TimedProgress =
styled.div <
TimedProgressProps >
`
- background-color: ${props => props.theme[ColorOption.primaryColor]};
- border-radius: 6px;
- height: 6px;
- animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)}
- ${props => props.timeMs}ms linear 1 forwards;
- `;
+ && {
+ background-color: ${props => props.theme[ColorOption.primaryColor]};
+ border-radius: 6px;
+ height: 6px;
+ animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)}
+ ${props => props.timeMs}ms linear 1 forwards;
+ }
+`;
diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx
index 5274d835b..b90221bf4 100644
--- a/packages/instant/src/components/ui/button.tsx
+++ b/packages/instant/src/components/ui/button.tsx
@@ -6,6 +6,8 @@ import { ColorOption, styled } from '../../style/theme';
export interface ButtonProps {
backgroundColor?: ColorOption;
borderColor?: ColorOption;
+ fontColor?: ColorOption;
+ fontSize?: string;
width?: string;
padding?: string;
type?: string;
@@ -24,29 +26,39 @@ const darkenOnHoverAmount = 0.1;
const darkenOnActiveAmount = 0.2;
const saturateOnFocusAmount = 0.2;
export const Button = styled(PlainButton)`
- cursor: ${props => (props.isDisabled ? 'default' : 'pointer')};
- transition: background-color, opacity 0.5s ease;
- padding: ${props => props.padding};
- border-radius: 3px;
- outline: none;
- width: ${props => props.width};
- background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
- border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')};
- &:hover {
- background-color: ${props =>
- !props.isDisabled
- ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white'])
- : ''} !important;
- }
- &:active {
- background-color: ${props =>
- !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''};
- }
- &:disabled {
- opacity: 0.5;
- }
- &:focus {
- background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])};
+ && {
+ all: initial;
+ box-sizing: border-box;
+ font-size: ${props => props.fontSize};
+ font-family: 'Inter UI', sans-serif;
+ font-weight: 600;
+ color: ${props => props.fontColor && props.theme[props.fontColor]};
+ cursor: ${props => (props.isDisabled ? 'default' : 'pointer')};
+ transition: background-color, opacity 0.5s ease;
+ padding: ${props => props.padding};
+ border-radius: 3px;
+ text-align: center;
+ outline: none;
+ width: ${props => props.width};
+ background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')};
+ &:hover {
+ background-color: ${props =>
+ !props.isDisabled
+ ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white'])
+ : ''} !important;
+ }
+ &:active {
+ background-color: ${props =>
+ !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''};
+ }
+ &:disabled {
+ opacity: 0.5;
+ }
+ &:focus {
+ background-color: ${props =>
+ saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])};
+ }
}
`;
@@ -55,7 +67,8 @@ Button.defaultProps = {
borderColor: ColorOption.primaryColor,
width: 'auto',
isDisabled: false,
- padding: '1em 2.2em',
+ padding: '.6em 1.2em',
+ fontSize: '15px',
};
Button.displayName = 'Button';
diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx
index eec2777d2..4f9f56f12 100644
--- a/packages/instant/src/components/ui/circle.tsx
+++ b/packages/instant/src/components/ui/circle.tsx
@@ -1,22 +1,27 @@
-import { styled } from '../../style/theme';
+import { ColorOption, styled, Theme, withTheme } from '../../style/theme';
export interface CircleProps {
diameter: number;
- fillColor?: string;
+ rawColor?: string;
+ color?: ColorOption;
+ theme: Theme;
}
-export const Circle =
+export const Circle = withTheme(
styled.div <
- CircleProps >
- `
- width: ${props => props.diameter}px;
- height: ${props => props.diameter}px;
- background-color: ${props => props.fillColor};
- border-radius: 50%;
-`;
+ CircleProps >
+ `
+ && {
+ width: ${props => props.diameter}px;
+ height: ${props => props.diameter}px;
+ background-color: ${props => (props.rawColor ? props.rawColor : props.theme[props.color || ColorOption.white])};
+ border-radius: 50%;
+ }
+`,
+);
Circle.displayName = 'Circle';
Circle.defaultProps = {
- fillColor: 'white',
+ color: ColorOption.white,
};
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
index a0a187e5f..8aa5db9e5 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -1,17 +1,18 @@
import { darken } from 'polished';
+import { MediaChoice, stylesForMedia } from '../../style/media';
import { ColorOption, styled } from '../../style/theme';
import { cssRuleIfExists } from '../../style/util';
export interface ContainerProps {
- display?: string;
+ display?: MediaChoice;
position?: string;
top?: string;
right?: string;
bottom?: string;
left?: string;
- width?: string;
- height?: string;
+ width?: MediaChoice;
+ height?: MediaChoice;
maxWidth?: string;
margin?: string;
marginTop?: string;
@@ -33,47 +34,53 @@ export interface ContainerProps {
cursor?: string;
overflow?: string;
darkenOnHover?: boolean;
+ boxShadowOnHover?: boolean;
+ flexGrow?: string | number;
}
export const Container =
styled.div <
ContainerProps >
`
- box-sizing: border-box;
- ${props => cssRuleIfExists(props, 'display')}
- ${props => cssRuleIfExists(props, 'position')}
- ${props => cssRuleIfExists(props, 'top')}
- ${props => cssRuleIfExists(props, 'right')}
- ${props => cssRuleIfExists(props, 'bottom')}
- ${props => cssRuleIfExists(props, 'left')}
- ${props => cssRuleIfExists(props, 'width')}
- ${props => cssRuleIfExists(props, 'height')}
- ${props => cssRuleIfExists(props, 'max-width')}
- ${props => cssRuleIfExists(props, 'margin')}
- ${props => cssRuleIfExists(props, 'margin-top')}
- ${props => cssRuleIfExists(props, 'margin-right')}
- ${props => cssRuleIfExists(props, 'margin-bottom')}
- ${props => cssRuleIfExists(props, 'margin-left')}
- ${props => cssRuleIfExists(props, 'padding')}
- ${props => cssRuleIfExists(props, 'border-radius')}
- ${props => cssRuleIfExists(props, 'border')}
- ${props => cssRuleIfExists(props, 'border-top')}
- ${props => cssRuleIfExists(props, 'border-bottom')}
- ${props => cssRuleIfExists(props, 'z-index')}
- ${props => cssRuleIfExists(props, 'white-space')}
- ${props => cssRuleIfExists(props, 'opacity')}
- ${props => cssRuleIfExists(props, 'cursor')}
- ${props => cssRuleIfExists(props, 'overflow')}
- ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
- background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
- border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
- &:hover {
- ${props =>
- props.darkenOnHover
- ? `background-color: ${
- props.backgroundColor ? darken(0.05, props.theme[props.backgroundColor]) : 'none'
- }`
- : ''};
+ && {
+ box-sizing: border-box;
+ ${props => cssRuleIfExists(props, 'flex-grow')}
+ ${props => cssRuleIfExists(props, 'position')}
+ ${props => cssRuleIfExists(props, 'top')}
+ ${props => cssRuleIfExists(props, 'right')}
+ ${props => cssRuleIfExists(props, 'bottom')}
+ ${props => cssRuleIfExists(props, 'left')}
+ ${props => cssRuleIfExists(props, 'max-width')}
+ ${props => cssRuleIfExists(props, 'margin')}
+ ${props => cssRuleIfExists(props, 'margin-top')}
+ ${props => cssRuleIfExists(props, 'margin-right')}
+ ${props => cssRuleIfExists(props, 'margin-bottom')}
+ ${props => cssRuleIfExists(props, 'margin-left')}
+ ${props => cssRuleIfExists(props, 'padding')}
+ ${props => cssRuleIfExists(props, 'border-radius')}
+ ${props => cssRuleIfExists(props, 'border')}
+ ${props => cssRuleIfExists(props, 'border-top')}
+ ${props => cssRuleIfExists(props, 'border-bottom')}
+ ${props => cssRuleIfExists(props, 'z-index')}
+ ${props => cssRuleIfExists(props, 'white-space')}
+ ${props => cssRuleIfExists(props, 'opacity')}
+ ${props => cssRuleIfExists(props, 'cursor')}
+ ${props => cssRuleIfExists(props, 'overflow')}
+ ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
+ ${props => props.display && stylesForMedia<string>('display', props.display)}
+ ${props => props.width && stylesForMedia<string>('width', props.width)}
+ ${props => props.height && stylesForMedia<string>('height', props.height)}
+ background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
+ &:hover {
+ ${props =>
+ props.darkenOnHover
+ ? `background-color: ${
+ props.backgroundColor ? darken(0.05, props.theme[props.backgroundColor]) : 'none'
+ }`
+ : ''};
+ ${props => (props.boxShadowOnHover ? 'box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)' : '')};
+ }
}
`;
diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx
new file mode 100644
index 000000000..3a23f456d
--- /dev/null
+++ b/packages/instant/src/components/ui/dropdown.tsx
@@ -0,0 +1,134 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { ColorOption, completelyTransparent } from '../../style/theme';
+import { zIndex } from '../../style/z_index';
+
+import { Container } from './container';
+import { Flex } from './flex';
+import { Icon } from './icon';
+import { Overlay } from './overlay';
+import { Text } from './text';
+
+export interface DropdownItemConfig {
+ text: string;
+ onClick?: () => void;
+}
+
+export interface DropdownProps {
+ value: string;
+ label?: string;
+ items: DropdownItemConfig[];
+}
+
+export interface DropdownState {
+ isOpen: boolean;
+}
+
+export class Dropdown extends React.Component<DropdownProps, DropdownState> {
+ public static defaultProps = {
+ items: [],
+ };
+ public state: DropdownState = {
+ isOpen: false,
+ };
+ public render(): React.ReactNode {
+ const { value, label, items } = this.props;
+ const { isOpen } = this.state;
+ const hasItems = !_.isEmpty(items);
+ const borderRadius = isOpen ? '4px 4px 0px 0px' : '4px';
+ return (
+ <React.Fragment>
+ {isOpen && (
+ <Overlay
+ zIndex={zIndex.dropdownItems - 1}
+ backgroundColor={completelyTransparent}
+ onClick={this._closeDropdown}
+ />
+ )}
+ <Container position="relative">
+ <Container
+ cursor={hasItems ? 'pointer' : undefined}
+ onClick={this._handleDropdownClick}
+ hasBoxShadow={isOpen}
+ boxShadowOnHover={true}
+ borderRadius={borderRadius}
+ border="1px solid"
+ borderColor={ColorOption.feintGrey}
+ padding="0.8em"
+ >
+ <Flex justify="space-between">
+ <Text fontSize="16px" fontColor={ColorOption.darkGrey}>
+ {value}
+ </Text>
+ <Container>
+ {label && (
+ <Text fontSize="16px" fontColor={ColorOption.lightGrey}>
+ {label}
+ </Text>
+ )}
+ {hasItems && (
+ <Container marginLeft="5px" display="inline-block" position="relative" bottom="2px">
+ <Icon padding="3px" icon="chevron" width={12} stroke={ColorOption.grey} />
+ </Container>
+ )}
+ </Container>
+ </Flex>
+ </Container>
+ {isOpen && (
+ <Container
+ width="100%"
+ position="absolute"
+ onClick={this._closeDropdown}
+ backgroundColor={ColorOption.white}
+ hasBoxShadow={true}
+ zIndex={zIndex.dropdownItems}
+ >
+ {_.map(items, (item, index) => (
+ <DropdownItem key={item.text} {...item} isLast={index === items.length - 1} />
+ ))}
+ </Container>
+ )}
+ </Container>
+ </React.Fragment>
+ );
+ }
+ private readonly _handleDropdownClick = (): void => {
+ if (_.isEmpty(this.props.items)) {
+ return;
+ }
+ this.setState({
+ isOpen: !this.state.isOpen,
+ });
+ };
+ private readonly _closeDropdown = (): void => {
+ this.setState({
+ isOpen: false,
+ });
+ };
+}
+
+export interface DropdownItemProps extends DropdownItemConfig {
+ text: string;
+ onClick?: () => void;
+ isLast: boolean;
+}
+
+export const DropdownItem: React.StatelessComponent<DropdownItemProps> = ({ text, onClick, isLast }) => (
+ <Container
+ onClick={onClick}
+ cursor="pointer"
+ darkenOnHover={true}
+ backgroundColor={ColorOption.white}
+ padding="0.8em"
+ borderTop="0"
+ border="1px solid"
+ borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
+ width="100%"
+ borderColor={ColorOption.feintGrey}
+ >
+ <Text fontSize="14px" fontColor={ColorOption.darkGrey}>
+ {text}
+ </Text>
+ </Container>
+);
diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx
index 29c6511bb..274c46b9e 100644
--- a/packages/instant/src/components/ui/flex.tsx
+++ b/packages/instant/src/components/ui/flex.tsx
@@ -1,3 +1,4 @@
+import { MediaChoice, stylesForMedia } from '../../style/media';
import { ColorOption, styled } from '../../style/theme';
import { cssRuleIfExists } from '../../style/util';
@@ -6,24 +7,28 @@ export interface FlexProps {
flexWrap?: 'wrap' | 'nowrap';
justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
- width?: string;
- height?: string;
+ width?: MediaChoice;
+ height?: MediaChoice;
backgroundColor?: ColorOption;
inline?: boolean;
+ flexGrow?: number | string;
}
export const Flex =
styled.div <
FlexProps >
`
- display: ${props => (props.inline ? 'inline-flex' : 'flex')};
- flex-direction: ${props => props.direction};
- flex-wrap: ${props => props.flexWrap};
- justify-content: ${props => props.justify};
- align-items: ${props => props.align};
- ${props => cssRuleIfExists(props, 'width')}
- ${props => cssRuleIfExists(props, 'height')}
- background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ && {
+ display: ${props => (props.inline ? 'inline-flex' : 'flex')};
+ flex-direction: ${props => props.direction};
+ flex-wrap: ${props => props.flexWrap};
+ ${props => cssRuleIfExists(props, 'flexGrow')}
+ justify-content: ${props => props.justify};
+ align-items: ${props => props.align};
+ background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ ${props => (props.width ? stylesForMedia('width', props.width) : '')}
+ ${props => (props.height ? stylesForMedia('height', props.height) : '')}
+ }
`;
Flex.defaultProps = {
diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx
index 94ea26900..a88fa87dd 100644
--- a/packages/instant/src/components/ui/icon.tsx
+++ b/packages/instant/src/components/ui/icon.tsx
@@ -9,7 +9,6 @@ interface IconInfo {
path: string;
fillRule?: svgRule;
clipRule?: svgRule;
- stroke?: string;
strokeOpacity?: number;
strokeWidth?: number;
strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
@@ -47,7 +46,6 @@ const ICONS: IconInfoMapping = {
chevron: {
viewBox: '0 0 12 7',
path: 'M11 1L6 6L1 1',
- stroke: 'white',
strokeOpacity: 0.5,
strokeWidth: 1.5,
strokeLinecap: 'round',
@@ -67,6 +65,7 @@ export interface IconProps {
width: number;
height?: number;
color?: ColorOption;
+ stroke?: ColorOption;
icon: keyof IconInfoMapping;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
padding?: string;
@@ -75,6 +74,7 @@ export interface IconProps {
const PlainIcon: React.StatelessComponent<IconProps> = props => {
const iconInfo = ICONS[props.icon];
const colorValue = _.isUndefined(props.color) ? undefined : props.theme[props.color];
+ const strokeValue = _.isUndefined(props.stroke) ? undefined : props.theme[props.stroke];
return (
<div onClick={props.onClick} className={props.className}>
<svg
@@ -89,7 +89,7 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
fill={colorValue}
fillRule={iconInfo.fillRule || 'nonzero'}
clipRule={iconInfo.clipRule || 'nonzero'}
- stroke={iconInfo.stroke}
+ stroke={strokeValue}
strokeOpacity={iconInfo.strokeOpacity}
strokeWidth={iconInfo.strokeWidth}
strokeLinecap={iconInfo.strokeLinecap}
@@ -101,15 +101,18 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
};
export const Icon = withTheme(styled(PlainIcon)`
- cursor: ${props => (!_.isUndefined(props.onClick) ? 'pointer' : 'default')};
- transition: opacity 0.5s ease;
- padding: ${props => props.padding};
- opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)};
- &:hover {
- opacity: 1;
- }
- &:active {
- opacity: 1;
+ && {
+ display: inline-block;
+ ${props => (!_.isUndefined(props.onClick) ? 'cursor: pointer' : '')};
+ transition: opacity 0.5s ease;
+ padding: ${props => props.padding};
+ opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)};
+ &:hover {
+ opacity: 1;
+ }
+ &:active {
+ opacity: 1;
+ }
}
`);
diff --git a/packages/instant/src/components/ui/index.ts b/packages/instant/src/components/ui/index.ts
deleted file mode 100644
index 87f5c11a1..000000000
--- a/packages/instant/src/components/ui/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export { Text, TextProps, Title } from './text';
-export { Circle, CircleProps } from './circle';
-export { Button, ButtonProps } from './button';
-export { Flex, FlexProps } from './flex';
-export { Container, ContainerProps } from './container';
-export { Input, InputProps } from './input';
-export { Icon, IconProps } from './icon';
-export { Spinner, SpinnerProps } from './spinner';
-export { Overlay, OverlayProps } from './overlay';
diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx
index a884ff7cb..2fb408db4 100644
--- a/packages/instant/src/components/ui/input.tsx
+++ b/packages/instant/src/components/ui/input.tsx
@@ -16,17 +16,20 @@ export const Input =
styled.input <
InputProps >
`
- font-size: ${props => props.fontSize};
- width: ${props => props.width};
- padding: 0.1em 0em;
- font-family: 'Inter UI';
- color: ${props => props.theme[props.fontColor || 'white']};
- background: transparent;
- outline: none;
- border: none;
- &::placeholder {
+ && {
+ all: initial;
+ font-size: ${props => props.fontSize};
+ width: ${props => props.width};
+ padding: 0.1em 0em;
+ font-family: 'Inter UI';
color: ${props => props.theme[props.fontColor || 'white']};
- opacity: 0.5;
+ background: transparent;
+ outline: none;
+ border: none;
+ &::placeholder {
+ color: ${props => props.theme[props.fontColor || 'white']};
+ opacity: 0.5;
+ }
}
`;
diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx
index f1706c874..f67d6fb2f 100644
--- a/packages/instant/src/components/ui/overlay.tsx
+++ b/packages/instant/src/components/ui/overlay.tsx
@@ -1,38 +1,39 @@
import * as _ from 'lodash';
-import * as React from 'react';
-import { ColorOption, overlayBlack, styled } from '../../style/theme';
-
-import { Container } from './container';
-import { Flex } from './flex';
-import { Icon } from './icon';
+import { generateMediaWrapper, ScreenWidths } from '../../style/media';
+import { generateOverlayBlack, styled } from '../../style/theme';
+import { zIndex } from '../../style/z_index';
export interface OverlayProps {
- className?: string;
- onClose?: () => void;
zIndex?: number;
+ backgroundColor?: string;
+ width?: string;
+ height?: string;
+ showMaxWidth?: ScreenWidths;
}
-const PlainOverlay: React.StatelessComponent<OverlayProps> = ({ children, className, onClose }) => (
- <Flex height="100vh" className={className}>
- <Container position="absolute" top="0px" right="0px">
- <Icon height={18} width={18} color={ColorOption.white} icon="closeX" onClick={onClose} padding="2em 2em" />
- </Container>
- <div>{children}</div>
- </Flex>
-);
-export const Overlay = styled(PlainOverlay)`
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: ${props => props.zIndex}
- background-color: ${overlayBlack};
+export const Overlay =
+ styled.div <
+ OverlayProps >
+ `
+ && {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: ${props => props.zIndex}
+ background-color: ${props => props.backgroundColor};
+ ${props => props.width && `width: ${props.width};`}
+ ${props => props.height && `height: ${props.height};`}
+ display: ${props => (props.showMaxWidth ? 'none' : 'block')};
+ ${props => props.showMaxWidth && generateMediaWrapper(props.showMaxWidth)`display: block;`}
+ }
`;
Overlay.defaultProps = {
- zIndex: 100,
+ zIndex: zIndex.overlayDefault,
+ backgroundColor: generateOverlayBlack(0.6),
};
Overlay.displayName = 'Overlay';
diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx
index cba6e7b20..4fe429d25 100644
--- a/packages/instant/src/components/ui/text.tsx
+++ b/packages/instant/src/components/ui/text.tsx
@@ -27,25 +27,27 @@ export const Text =
styled.div <
TextProps >
`
- font-family: ${props => props.fontFamily};
- font-style: ${props => props.fontStyle};
- font-weight: ${props => props.fontWeight};
- font-size: ${props => props.fontSize};
- opacity: ${props => props.opacity};
- text-decoration-line: ${props => props.textDecorationLine};
- ${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')};
- ${props => (props.center ? 'text-align: center' : '')};
- color: ${props => props.fontColor && props.theme[props.fontColor]};
- ${props => (props.minHeight ? `min-height: ${props.minHeight}` : '')};
- ${props => (props.onClick ? 'cursor: pointer' : '')};
- transition: color 0.5s ease;
- ${props => (props.noWrap ? 'white-space: nowrap' : '')};
- ${props => (props.display ? `display: ${props.display}` : '')};
- ${props => (props.letterSpacing ? `letter-spacing: ${props.letterSpacing}` : '')};
- ${props => (props.textTransform ? `text-transform: ${props.textTransform}` : '')};
- &:hover {
- ${props =>
- props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''};
+ && {
+ font-family: 'Inter UI', sans-serif;
+ font-style: ${props => props.fontStyle};
+ font-weight: ${props => props.fontWeight};
+ font-size: ${props => props.fontSize};
+ opacity: ${props => props.opacity};
+ text-decoration-line: ${props => props.textDecorationLine};
+ ${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')};
+ ${props => (props.center ? 'text-align: center' : '')};
+ color: ${props => props.fontColor && props.theme[props.fontColor]};
+ ${props => (props.minHeight ? `min-height: ${props.minHeight}` : '')};
+ ${props => (props.onClick ? 'cursor: pointer' : '')};
+ transition: color 0.5s ease;
+ ${props => (props.noWrap ? 'white-space: nowrap' : '')};
+ ${props => (props.display ? `display: ${props.display}` : '')};
+ ${props => (props.letterSpacing ? `letter-spacing: ${props.letterSpacing}` : '')};
+ ${props => (props.textTransform ? `text-transform: ${props.textTransform}` : '')};
+ &:hover {
+ ${props =>
+ props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''};
+ }
}
`;
@@ -61,14 +63,3 @@ Text.defaultProps = {
};
Text.displayName = 'Text';
-
-export const Title: React.StatelessComponent<TextProps> = props => <Text {...props} />;
-
-Title.defaultProps = {
- fontSize: '20px',
- fontWeight: 600,
- opacity: 1,
- fontColor: ColorOption.primaryColor,
-};
-
-Title.displayName = 'Title';
diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx
index 907c42e7a..b945f9908 100644
--- a/packages/instant/src/components/zero_ex_instant.tsx
+++ b/packages/instant/src/components/zero_ex_instant.tsx
@@ -1,5 +1,7 @@
import * as React from 'react';
+import { INJECTED_DIV_CLASS } from '../constants';
+
import { ZeroExInstantContainer } from './zero_ex_instant_container';
import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider';
@@ -7,8 +9,10 @@ export type ZeroExInstantProps = ZeroExInstantProviderProps;
export const ZeroExInstant: React.StatelessComponent<ZeroExInstantProps> = props => {
return (
- <ZeroExInstantProvider {...props}>
- <ZeroExInstantContainer />
- </ZeroExInstantProvider>
+ <div className={INJECTED_DIV_CLASS}>
+ <ZeroExInstantProvider {...props}>
+ <ZeroExInstantContainer />
+ </ZeroExInstantProvider>
+ </div>
);
};
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index c1bd17502..5748e064e 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -3,17 +3,18 @@ import * as React from 'react';
import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector';
import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
import { LatestError } from '../containers/latest_error';
+import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress';
import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons';
import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
-
-import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress';
-
import { ColorOption } from '../style/theme';
import { zIndex } from '../style/z_index';
import { SlideAnimationState } from './animations/slide_animation';
+import { CSSReset } from './css_reset';
import { SlidingPanel } from './sliding_panel';
-import { Container, Flex } from './ui';
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+
export interface ZeroExInstantContainerProps {}
export interface ZeroExInstantContainerState {
tokenSelectionPanelAnimationState: SlideAnimationState;
@@ -25,35 +26,43 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
};
public render(): React.ReactNode {
return (
- <Container width="350px" position="relative">
- <Container zIndex={zIndex.errorPopup} position="relative">
- <LatestError />
- </Container>
+ <React.Fragment>
+ <CSSReset />
<Container
- zIndex={zIndex.mainContainer}
+ width={{ default: '350px', sm: '100%' }}
+ height={{ default: 'auto', sm: '100%' }}
position="relative"
- backgroundColor={ColorOption.white}
- borderRadius="3px"
- hasBoxShadow={true}
- overflow="hidden"
>
- <Flex direction="column" justify="flex-start">
- <SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} />
- <SelectedAssetBuyOrderProgress />
- <LatestBuyQuoteOrderDetails />
- <Container padding="20px" width="100%">
- <SelectedAssetBuyOrderStateButtons />
- </Container>
- </Flex>
- <SlidingPanel
- title="Select Token"
- animationState={this.state.tokenSelectionPanelAnimationState}
- onClose={this._handlePanelClose}
+ <Container position="relative">
+ <LatestError />
+ </Container>
+ <Container
+ zIndex={zIndex.mainContainer}
+ position="relative"
+ backgroundColor={ColorOption.white}
+ borderRadius="3px"
+ hasBoxShadow={true}
+ overflow="hidden"
+ height="100%"
>
- <AvailableERC20TokenSelector onTokenSelect={this._handlePanelClose} />
- </SlidingPanel>
+ <Flex direction="column" justify="flex-start" height="100%">
+ <SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} />
+ <SelectedAssetBuyOrderProgress />
+ <LatestBuyQuoteOrderDetails />
+ <Container padding="20px" width="100%">
+ <SelectedAssetBuyOrderStateButtons />
+ </Container>
+ </Flex>
+ <SlidingPanel
+ title="Select Token"
+ animationState={this.state.tokenSelectionPanelAnimationState}
+ onClose={this._handlePanelClose}
+ >
+ <AvailableERC20TokenSelector onTokenSelect={this._handlePanelClose} />
+ </SlidingPanel>
+ </Container>
</Container>
- </Container>
+ </React.Fragment>
);
}
private readonly _handleSymbolClick = (): void => {
diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx
index 8f872f896..10438ab7a 100644
--- a/packages/instant/src/components/zero_ex_instant_overlay.tsx
+++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx
@@ -1,6 +1,11 @@
import * as React from 'react';
-import { Overlay } from './ui';
+import { ColorOption } from '../style/theme';
+
+import { Container } from './ui/container';
+import { Flex } from './ui/flex';
+import { Icon } from './ui/icon';
+import { Overlay } from './ui/overlay';
import { ZeroExInstantContainer } from './zero_ex_instant_container';
import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider';
@@ -13,8 +18,22 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay
const { onClose, zIndex, ...rest } = props;
return (
<ZeroExInstantProvider {...rest}>
- <Overlay onClose={onClose} zIndex={zIndex}>
- <ZeroExInstantContainer />
+ <Overlay zIndex={zIndex}>
+ <Flex height="100vh">
+ <Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}>
+ <Icon
+ height={18}
+ width={18}
+ color={ColorOption.white}
+ icon="closeX"
+ onClick={onClose}
+ padding="2em 2em"
+ />
+ </Container>
+ <Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}>
+ <ZeroExInstantContainer />
+ </Container>
+ </Flex>
</Overlay>
</ZeroExInstantProvider>
);
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 0b9408329..411f118cc 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -1,23 +1,23 @@
-import { AssetBuyer } from '@0x/asset-buyer';
-import { ObjectMap, SignedOrder } from '@0x/types';
+import { ObjectMap } from '@0x/types';
import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
import * as React from 'react';
import { Provider as ReduxProvider } from 'react-redux';
-import { oc } from 'ts-optchain';
+import { ACCOUNT_UPDATE_INTERVAL_TIME_MS, BUY_QUOTE_UPDATE_INTERVAL_TIME_MS } from '../constants';
import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider';
import { asyncData } from '../redux/async_data';
-import { INITIAL_STATE, State } from '../redux/reducer';
+import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer';
import { store, Store } from '../redux/store';
import { fonts } from '../style/fonts';
-import { AffiliateInfo, AssetMetaData, Network } from '../types';
+import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types';
import { assetUtils } from '../util/asset';
import { errorFlasher } from '../util/error_flasher';
import { gasPriceEstimator } from '../util/gas_price_estimator';
-import { getInjectedProvider } from '../util/injected_provider';
+import { Heartbeater } from '../util/heartbeater';
+import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory';
+import { providerStateFactory } from '../util/provider_state_factory';
fonts.include();
@@ -25,7 +25,7 @@ export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps &
Partial<ZeroExInstantProviderOptionalProps>;
export interface ZeroExInstantProviderRequiredProps {
- orderSource: string | SignedOrder[];
+ orderSource: OrderSource;
}
export interface ZeroExInstantProviderOptionalProps {
@@ -40,31 +40,31 @@ export interface ZeroExInstantProviderOptionalProps {
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
private readonly _store: Store;
+ private _accountUpdateHeartbeat?: Heartbeater;
+ private _buyQuoteHeartbeat?: Heartbeater;
+
// TODO(fragosti): Write tests for this beast once we inject a provider.
- private static _mergeInitialStateWithProps(props: ZeroExInstantProviderProps, state: State = INITIAL_STATE): State {
- const networkId = props.networkId || state.network;
- // TODO: Proper wallet connect flow
- const provider = props.provider || getInjectedProvider();
- const assetBuyerOptions = {
+ private static _mergeDefaultStateWithProps(
+ props: ZeroExInstantProviderProps,
+ defaultState: DefaultState = DEFAULT_STATE,
+ ): State {
+ // use the networkId passed in with the props, otherwise default to that of the default state (1, mainnet)
+ const networkId = props.networkId || defaultState.network;
+ // construct the ProviderState
+ const providerState = providerStateFactory.getInitialProviderState(
+ props.orderSource,
networkId,
- };
- let assetBuyer;
- if (_.isString(props.orderSource)) {
- assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(
- provider,
- props.orderSource,
- assetBuyerOptions,
- );
- } else {
- assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.orderSource, assetBuyerOptions);
- }
+ props.provider,
+ );
+ // merge the additional additionalAssetMetaDataMap with our default map
const completeAssetMetaDataMap = {
...props.additionalAssetMetaDataMap,
- ...state.assetMetaDataMap,
+ ...defaultState.assetMetaDataMap,
};
+ // construct the final state
const storeStateFromProps: State = {
- ...state,
- assetBuyer,
+ ...defaultState,
+ providerState,
network: networkId,
selectedAsset: _.isUndefined(props.defaultSelectedAssetData)
? undefined
@@ -74,7 +74,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
networkId,
),
selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount)
- ? state.selectedAssetAmount
+ ? undefined
: new BigNumber(props.defaultAssetBuyAmount),
availableAssets: _.isUndefined(props.availableAssetDatas)
? undefined
@@ -86,10 +86,9 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
}
constructor(props: ZeroExInstantProviderProps) {
super(props);
- const initialAppState = ZeroExInstantProvider._mergeInitialStateWithProps(this.props, INITIAL_STATE);
+ const initialAppState = ZeroExInstantProvider._mergeDefaultStateWithProps(this.props);
this._store = store.create(initialAppState);
}
-
public componentDidMount(): void {
const state = this._store.getState();
// tslint:disable-next-line:no-floating-promises
@@ -99,16 +98,36 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
// tslint:disable-next-line:no-floating-promises
asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
}
+ if (state.providerState.account.state !== AccountState.None) {
+ this._accountUpdateHeartbeat = generateAccountHeartbeater({
+ store: this._store,
+ shouldPerformImmediatelyOnStart: true,
+ });
+ this._accountUpdateHeartbeat.start(ACCOUNT_UPDATE_INTERVAL_TIME_MS);
+ }
+ this._buyQuoteHeartbeat = generateBuyQuoteHeartbeater({
+ store: this._store,
+ shouldPerformImmediatelyOnStart: false,
+ });
+ this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS);
+ // tslint:disable-next-line:no-floating-promises
+ asyncData.fetchCurrentBuyQuoteAndDispatchToStore({ store: this._store, shouldSetPending: true });
// warm up the gas price estimator cache just in case we can't
// grab the gas price estimate when submitting the transaction
// tslint:disable-next-line:no-floating-promises
gasPriceEstimator.getGasInfoAsync();
-
// tslint:disable-next-line:no-floating-promises
this._flashErrorIfWrongNetwork();
}
-
+ public componentWillUnmount(): void {
+ if (this._accountUpdateHeartbeat) {
+ this._accountUpdateHeartbeat.stop();
+ }
+ if (this._buyQuoteHeartbeat) {
+ this._buyQuoteHeartbeat.stop();
+ }
+ }
public render(): React.ReactNode {
return (
<ReduxProvider store={this._store}>
@@ -116,19 +135,15 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
</ReduxProvider>
);
}
-
private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => {
const msToShowError = 30000; // 30 seconds
- const network = this._store.getState().network;
- const assetBuyerIfExists = this._store.getState().assetBuyer;
- const providerIfExists = oc(assetBuyerIfExists).provider();
- if (!_.isUndefined(providerIfExists)) {
- const web3Wrapper = new Web3Wrapper(providerIfExists);
- const networkOfProvider = await web3Wrapper.getNetworkIdAsync();
- if (network !== networkOfProvider) {
- const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`;
- errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError);
- }
+ const state = this._store.getState();
+ const network = state.network;
+ const web3Wrapper = state.providerState.web3Wrapper;
+ const networkOfProvider = await web3Wrapper.getNetworkIdAsync();
+ if (network !== networkOfProvider) {
+ const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`;
+ errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError);
}
};
}
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index 15105b65c..110a8248a 100644
--- a/packages/instant/src/constants.ts
+++ b/packages/instant/src/constants.ts
@@ -1,15 +1,35 @@
import { BigNumber } from '@0x/utils';
+
+import { AccountNotReady, AccountState, Network } from './types';
+
export const BIG_NUMBER_ZERO = new BigNumber(0);
export const ETH_DECIMALS = 18;
export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer';
+export const INJECTED_DIV_CLASS = 'zeroExInstantResetRoot';
export const INJECTED_DIV_ID = 'zeroExInstant';
export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed';
export const GWEI_IN_WEI = new BigNumber(1000000000);
export const ONE_SECOND_MS = 1000;
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
+export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5;
+export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15;
export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6);
export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2';
export const PROGRESS_STALL_AT_WIDTH = '95%';
export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200;
+export const ETHEREUM_NODE_URL_BY_NETWORK = {
+ [Network.Mainnet]: 'https://mainnet.infura.io/',
+ [Network.Kovan]: 'https://kovan.infura.io/',
+};
+export const BLOCK_POLLING_INTERVAL_MS = 10000; // 10s
+export const NO_ACCOUNT: AccountNotReady = {
+ state: AccountState.None,
+};
+export const LOADING_ACCOUNT: AccountNotReady = {
+ state: AccountState.Loading,
+};
+export const LOCKED_ACCOUNT: AccountNotReady = {
+ state: AccountState.Locked,
+};
diff --git a/packages/instant/src/containers/latest_buy_quote_order_details.ts b/packages/instant/src/containers/latest_buy_quote_order_details.ts
index 092aaaf20..2b59ed3ae 100644
--- a/packages/instant/src/containers/latest_buy_quote_order_details.ts
+++ b/packages/instant/src/containers/latest_buy_quote_order_details.ts
@@ -22,7 +22,7 @@ const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProp
// use the worst case quote info
buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(),
ethUsdPrice: state.ethUsdPrice,
- isLoading: state.quoteRequestState === AsyncProcessState.PENDING,
+ isLoading: state.quoteRequestState === AsyncProcessState.Pending,
});
export const LatestBuyQuoteOrderDetails: React.ComponentClass<LatestBuyQuoteOrderDetailsProps> = connect(
diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx
index 99e55a6c4..c0da181f1 100644
--- a/packages/instant/src/containers/latest_error.tsx
+++ b/packages/instant/src/containers/latest_error.tsx
@@ -1,35 +1,60 @@
import * as React from 'react';
import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
import { SlideAnimationState } from '../components/animations/slide_animation';
import { SlidingError } from '../components/sliding_error';
+import { Overlay } from '../components/ui/overlay';
+import { Action } from '../redux/actions';
import { State } from '../redux/reducer';
-import { Asset, DisplayStatus } from '../types';
+import { ScreenWidths } from '../style/media';
+import { generateOverlayBlack } from '../style/theme';
+import { zIndex } from '../style/z_index';
+import { Asset, DisplayStatus, Omit } from '../types';
+import { errorFlasher } from '../util/error_flasher';
export interface LatestErrorComponentProps {
asset?: Asset;
latestErrorMessage?: string;
animationState: SlideAnimationState;
+ shouldRenderOverlay: boolean;
+ onOverlayClick: () => void;
}
export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
if (!props.latestErrorMessage) {
return <div />;
}
- return <SlidingError animationState={props.animationState} icon="😢" message={props.latestErrorMessage} />;
+ return (
+ <React.Fragment>
+ <SlidingError animationState={props.animationState} icon="😢" message={props.latestErrorMessage} />
+ {props.shouldRenderOverlay && (
+ <Overlay
+ onClick={props.onOverlayClick}
+ zIndex={zIndex.containerOverlay}
+ showMaxWidth={ScreenWidths.Sm}
+ backgroundColor={generateOverlayBlack(0.4)}
+ />
+ )}
+ </React.Fragment>
+ );
};
-interface ConnectedState {
- asset?: Asset;
- latestErrorMessage?: string;
- animationState: SlideAnimationState;
-}
export interface LatestErrorProps {}
+interface ConnectedState extends Omit<LatestErrorComponentProps, 'onOverlayClick'> {}
const mapStateToProps = (state: State, _ownProps: LatestErrorProps): ConnectedState => ({
asset: state.selectedAsset,
latestErrorMessage: state.latestErrorMessage,
animationState: state.latestErrorDisplayStatus === DisplayStatus.Present ? 'slidIn' : 'slidOut',
+ shouldRenderOverlay: state.latestErrorDisplayStatus === DisplayStatus.Present,
+});
+
+type ConnectedDispatch = Pick<LatestErrorComponentProps, 'onOverlayClick'>;
+const mapDispatchToProps = (dispatch: Dispatch<Action>, _ownProps: LatestErrorProps): ConnectedDispatch => ({
+ onOverlayClick: () => {
+ errorFlasher.clearError(dispatch);
+ },
});
-export const LatestError = connect(mapStateToProps)(LatestErrorComponent);
+export const LatestError = connect(mapStateToProps, mapDispatchToProps)(LatestErrorComponent);
diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
index 72d99f844..610335243 100644
--- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
+++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
@@ -1,4 +1,6 @@
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
@@ -7,14 +9,17 @@ import { Dispatch } from 'redux';
import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
-import { AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
+import { AccountState, AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
import { errorFlasher } from '../util/error_flasher';
import { etherscanUtil } from '../util/etherscan';
interface ConnectedState {
+ accountAddress?: string;
+ accountEthBalanceInWei?: BigNumber;
buyQuote?: BuyQuote;
buyOrderProcessingState: OrderProcessState;
- assetBuyer?: AssetBuyer;
+ assetBuyer: AssetBuyer;
+ web3Wrapper: Web3Wrapper;
affiliateInfo?: AffiliateInfo;
onViewTransaction: () => void;
}
@@ -29,29 +34,38 @@ interface ConnectedDispatch {
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
}
export interface SelectedAssetBuyOrderStateButtons {}
-const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({
- buyOrderProcessingState: state.buyOrderState.processState,
- assetBuyer: state.assetBuyer,
- buyQuote: state.latestBuyQuote,
- affiliateInfo: state.affiliateInfo,
- 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 mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => {
+ const assetBuyer = state.providerState.assetBuyer;
+ const web3Wrapper = state.providerState.web3Wrapper;
+ const account = state.providerState.account;
+ const accountAddress = account.state === AccountState.Ready ? account.address : undefined;
+ const accountEthBalanceInWei = account.state === AccountState.Ready ? account.ethBalanceInWei : undefined;
+ return {
+ accountAddress,
+ accountEthBalanceInWei,
+ buyOrderProcessingState: state.buyOrderState.processState,
+ assetBuyer,
+ web3Wrapper,
+ buyQuote: state.latestBuyQuote,
+ affiliateInfo: state.affiliateInfo,
+ onViewTransaction: () => {
+ if (
+ state.buyOrderState.processState === OrderProcessState.Processing ||
+ state.buyOrderState.processState === OrderProcessState.Success ||
+ state.buyOrderState.processState === OrderProcessState.Failure
+ ) {
+ const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists(
+ state.buyOrderState.txHash,
+ assetBuyer.networkId,
+ );
+ if (etherscanUrl) {
+ window.open(etherscanUrl, '_blank');
+ return;
+ }
}
- }
- },
-});
+ },
+ };
+};
const mapDispatchToProps = (
dispatch: Dispatch<Action>,
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 f7d56c564..93ff3db70 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -1,20 +1,17 @@
-import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { AssetBuyer } from '@0x/asset-buyer';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
-import { oc } from 'ts-optchain';
import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { ColorOption } from '../style/theme';
import { AffiliateInfo, ERC20Asset, OrderProcessState } from '../types';
-import { assetUtils } from '../util/asset';
-import { errorFlasher } from '../util/error_flasher';
+import { buyQuoteUpdater } from '../util/buy_quote_updater';
export interface SelectedERC20AssetAmountInputProps {
fontColor?: ColorOption;
@@ -23,7 +20,7 @@ export interface SelectedERC20AssetAmountInputProps {
}
interface ConnectedState {
- assetBuyer?: AssetBuyer;
+ assetBuyer: AssetBuyer;
value?: BigNumber;
asset?: ERC20Asset;
isDisabled: boolean;
@@ -33,7 +30,7 @@ interface ConnectedState {
interface ConnectedDispatch {
updateBuyQuote: (
- assetBuyer?: AssetBuyer,
+ assetBuyer: AssetBuyer,
value?: BigNumber,
asset?: ERC20Asset,
affiliateInfo?: AffiliateInfo,
@@ -52,15 +49,16 @@ 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 isEnabled = processState === OrderProcessState.None || processState === OrderProcessState.Failure;
const isDisabled = !isEnabled;
const selectedAsset =
!_.isUndefined(state.selectedAsset) && state.selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
? (state.selectedAsset as ERC20Asset)
: undefined;
const numberOfAssetsAvailable = _.isUndefined(state.availableAssets) ? undefined : state.availableAssets.length;
+ const assetBuyer = state.providerState.assetBuyer;
return {
- assetBuyer: state.assetBuyer,
+ assetBuyer,
value: state.selectedAssetAmount,
asset: selectedAsset,
isDisabled,
@@ -69,52 +67,9 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP
};
};
-const updateBuyQuoteAsync = async (
- assetBuyer: AssetBuyer,
- dispatch: Dispatch<Action>,
- asset: ERC20Asset,
- assetAmount: BigNumber,
- affiliateInfo?: AffiliateInfo,
-): Promise<void> => {
- // get a new buy quote.
- const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals);
-
- // mark quote as pending
- dispatch(actions.setQuoteRequestStatePending());
-
- const feePercentage = oc(affiliateInfo).feePercentage();
- let newBuyQuote: BuyQuote | undefined;
- try {
- newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
- } catch (error) {
- dispatch(actions.setQuoteRequestStateFailure());
- let errorMessage;
- if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
- const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
- errorMessage = `Not enough ${assetName} available`;
- } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
- errorMessage = 'Not enough ZRX available';
- } else if (
- error.message === AssetBuyerError.StandardRelayerApiError ||
- error.message.startsWith(AssetBuyerError.AssetUnavailable)
- ) {
- const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
- errorMessage = `${assetName} is currently unavailable`;
- }
- if (!_.isUndefined(errorMessage)) {
- errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
- } else {
- throw error;
- }
- return;
- }
- // We have a successful new buy quote
- errorFlasher.clearError(dispatch);
- // invalidate the last buy quote.
- dispatch(actions.updateLatestBuyQuote(newBuyQuote));
-};
-
-const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trailing: true });
+const debouncedUpdateBuyQuoteAsync = _.debounce(buyQuoteUpdater.updateBuyQuoteAsync.bind(buyQuoteUpdater), 200, {
+ trailing: true,
+}) as typeof buyQuoteUpdater.updateBuyQuoteAsync;
const mapDispatchToProps = (
dispatch: Dispatch<Action>,
@@ -128,11 +83,11 @@ const mapDispatchToProps = (
// reset our buy state
dispatch(actions.setBuyOrderStateNone());
- if (!_.isUndefined(value) && value.greaterThan(0) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) {
+ if (!_.isUndefined(value) && value.greaterThan(0) && !_.isUndefined(asset)) {
// even if it's debounced, give them the illusion it's loading
dispatch(actions.setQuoteRequestStatePending());
// tslint:disable-next-line:no-floating-promises
- debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, affiliateInfo);
+ debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, true, affiliateInfo);
}
},
});
diff --git a/packages/instant/src/data/asset_data_network_mapping.ts b/packages/instant/src/data/asset_data_network_mapping.ts
index 43bd34697..4fd0a25ed 100644
--- a/packages/instant/src/data/asset_data_network_mapping.ts
+++ b/packages/instant/src/data/asset_data_network_mapping.ts
@@ -26,7 +26,8 @@ export const assetDataNetworkMapping: AssetDataByNetwork[] = [
// MKR
{
[Network.Mainnet]: '0xf47261b00000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2',
- [Network.Kovan]: '0xf47261b00000000000000000000000000xbf5e8e38659562fda594fbb3ec5a3576d02a9e0a',
+ // 0x Kovan MKR
+ [Network.Kovan]: '0xf47261b00000000000000000000000007b6b10caa9e8e9552ba72638ea5b47c25afea1f3',
},
// BAT
{
@@ -45,8 +46,9 @@ export const assetDataNetworkMapping: AssetDataByNetwork[] = [
},
// GNT
{
- [Network.Mainnet]: '0xf47261b0000000000000000000000000a74476443119A942dE498590Fe1f2454d7D4aC0d',
- [Network.Kovan]: '0xf47261b00000000000000000000000006986fa3646f408905ecb1876bfd355d25039ee3a',
+ [Network.Mainnet]: '0xf47261b0000000000000000000000000a74476443119a942de498590fe1f2454d7d4ac0d',
+ // 0x Kovan GNT
+ [Network.Kovan]: '0xf47261b000000000000000000000000031fb614e223706f15d0d3c5f4b08bdf0d5c78623',
},
// SUB
{
diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts
index 8a0f29e21..970b6c383 100644
--- a/packages/instant/src/data/asset_meta_data_map.ts
+++ b/packages/instant/src/data/asset_meta_data_map.ts
@@ -54,7 +54,7 @@ export const assetMetaDataMap: ObjectMap<AssetMetaData> = {
symbol: 'mana',
name: 'Decentraland',
},
- '0xf47261b0000000000000000000000000a74476443119A942dE498590Fe1f2454d7D4aC0d': {
+ '0xf47261b0000000000000000000000000a74476443119a942de498590fe1f2454d7d4ac0d': {
assetProxyId: AssetProxyId.ERC20,
decimals: 18,
primaryColor: '#263469',
diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts
index 59d1e646f..0274db30c 100644
--- a/packages/instant/src/index.umd.ts
+++ b/packages/instant/src/index.umd.ts
@@ -2,7 +2,7 @@ import * as _ from 'lodash';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
-import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_ID } from './constants';
+import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants';
import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index';
import { assert } from './util/assert';
@@ -41,6 +41,7 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA
const appendTo = appendToIfExists as Element;
const injectedDiv = document.createElement('div');
injectedDiv.setAttribute('id', INJECTED_DIV_ID);
+ injectedDiv.setAttribute('class', INJECTED_DIV_CLASS);
appendTo.appendChild(injectedDiv);
const instantOverlayProps = {
...props,
diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts
index c41c5054b..8947c6c97 100644
--- a/packages/instant/src/redux/actions.ts
+++ b/packages/instant/src/redux/actions.ts
@@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
-import { ActionsUnion, Asset } from '../types';
+import { ActionsUnion, AddressAndEthBalanceInWei, Asset } from '../types';
export interface PlainAction<T extends string> {
type: T;
@@ -21,6 +21,10 @@ function createAction<T extends string, P>(type: T, data?: P): PlainAction<T> |
}
export enum ActionTypes {
+ SET_ACCOUNT_STATE_LOADING = 'SET_ACCOUNT_STATE_LOADING',
+ SET_ACCOUNT_STATE_LOCKED = 'SET_ACCOUNT_STATE_LOCKED',
+ SET_ACCOUNT_STATE_READY = 'SET_ACCOUNT_STATE_READY',
+ UPDATE_ACCOUNT_ETH_BALANCE = 'UPDATE_ACCOUNT_ETH_BALANCE',
UPDATE_ETH_USD_PRICE = 'UPDATE_ETH_USD_PRICE',
UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT',
SET_BUY_ORDER_STATE_NONE = 'SET_BUY_ORDER_STATE_NONE',
@@ -40,6 +44,11 @@ export enum ActionTypes {
}
export const actions = {
+ setAccountStateLoading: () => createAction(ActionTypes.SET_ACCOUNT_STATE_LOADING),
+ setAccountStateLocked: () => createAction(ActionTypes.SET_ACCOUNT_STATE_LOCKED),
+ setAccountStateReady: (address: string) => createAction(ActionTypes.SET_ACCOUNT_STATE_READY, address),
+ updateAccountEthBalance: (addressAndBalance: AddressAndEthBalanceInWei) =>
+ createAction(ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE, addressAndBalance),
updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price),
updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount),
setBuyOrderStateNone: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_NONE),
diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts
index 0e05c13da..b920ac914 100644
--- a/packages/instant/src/redux/async_data.ts
+++ b/packages/instant/src/redux/async_data.ts
@@ -1,7 +1,10 @@
+import { AssetProxyId } from '@0x/types';
import * as _ from 'lodash';
import { BIG_NUMBER_ZERO } from '../constants';
+import { AccountState, ERC20Asset, OrderProcessState } from '../types';
import { assetUtils } from '../util/asset';
+import { buyQuoteUpdater } from '../util/buy_quote_updater';
import { coinbaseApi } from '../util/coinbase_api';
import { errorFlasher } from '../util/error_flasher';
@@ -20,18 +23,81 @@ export const asyncData = {
}
},
fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => {
- const { assetBuyer, assetMetaDataMap, network } = store.getState();
- if (!_.isUndefined(assetBuyer)) {
- try {
- const assetDatas = await assetBuyer.getAvailableAssetDatasAsync();
- const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network);
- store.dispatch(actions.setAvailableAssets(assets));
- } catch (e) {
- const errorMessage = 'Could not find any assets';
- errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage);
- // On error, just specify that none are available
- store.dispatch(actions.setAvailableAssets([]));
- }
+ const { providerState, assetMetaDataMap, network } = store.getState();
+ const assetBuyer = providerState.assetBuyer;
+ try {
+ const assetDatas = await assetBuyer.getAvailableAssetDatasAsync();
+ const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network);
+ store.dispatch(actions.setAvailableAssets(assets));
+ } catch (e) {
+ const errorMessage = 'Could not find any assets';
+ errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage);
+ // On error, just specify that none are available
+ store.dispatch(actions.setAvailableAssets([]));
+ }
+ },
+ fetchAccountInfoAndDispatchToStore: async (options: { store: Store; shouldSetToLoading: boolean }) => {
+ const { store, shouldSetToLoading } = options;
+ const { providerState } = store.getState();
+ const web3Wrapper = providerState.web3Wrapper;
+ const provider = providerState.provider;
+ if (shouldSetToLoading && providerState.account.state !== AccountState.Loading) {
+ store.dispatch(actions.setAccountStateLoading());
+ }
+ let availableAddresses: string[];
+ try {
+ // TODO(bmillman): Add support at the web3Wrapper level for calling `eth_requestAccounts` instead of calling enable here
+ const isPrivacyModeEnabled = !_.isUndefined((provider as any).enable);
+ availableAddresses = isPrivacyModeEnabled
+ ? await (provider as any).enable()
+ : await web3Wrapper.getAvailableAddressesAsync();
+ } catch (e) {
+ store.dispatch(actions.setAccountStateLocked());
+ return;
+ }
+ if (!_.isEmpty(availableAddresses)) {
+ const activeAddress = availableAddresses[0];
+ store.dispatch(actions.setAccountStateReady(activeAddress));
+ // tslint:disable-next-line:no-floating-promises
+ asyncData.fetchAccountBalanceAndDispatchToStore(store);
+ } else {
+ store.dispatch(actions.setAccountStateLocked());
+ }
+ },
+ fetchAccountBalanceAndDispatchToStore: async (store: Store) => {
+ const { providerState } = store.getState();
+ const web3Wrapper = providerState.web3Wrapper;
+ const account = providerState.account;
+ if (account.state !== AccountState.Ready) {
+ return;
+ }
+ try {
+ const address = account.address;
+ const ethBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(address);
+ store.dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei }));
+ } catch (e) {
+ // leave balance as is
+ return;
+ }
+ },
+ fetchCurrentBuyQuoteAndDispatchToStore: async (options: { store: Store; shouldSetPending: boolean }) => {
+ const { store, shouldSetPending } = options;
+ const { buyOrderState, providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = store.getState();
+ const assetBuyer = providerState.assetBuyer;
+ if (
+ !_.isUndefined(selectedAssetAmount) &&
+ !_.isUndefined(selectedAsset) &&
+ buyOrderState.processState === OrderProcessState.None &&
+ selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
+ ) {
+ await buyQuoteUpdater.updateBuyQuoteAsync(
+ assetBuyer,
+ store.dispatch,
+ selectedAsset as ERC20Asset,
+ selectedAssetAmount,
+ shouldSetPending,
+ affiliateInfo,
+ );
}
},
};
diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts
index bc435d069..ef46fdd9d 100644
--- a/packages/instant/src/redux/reducer.ts
+++ b/packages/instant/src/redux/reducer.ts
@@ -1,11 +1,15 @@
-import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
+import { BuyQuote } from '@0x/asset-buyer';
import { AssetProxyId, ObjectMap } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
+import { LOADING_ACCOUNT, LOCKED_ACCOUNT } from '../constants';
import { assetMetaDataMap } from '../data/asset_meta_data_map';
import {
+ Account,
+ AccountReady,
+ AccountState,
AffiliateInfo,
Asset,
AssetMetaData,
@@ -14,172 +18,216 @@ import {
Network,
OrderProcessState,
OrderState,
+ ProviderState,
} from '../types';
import { Action, ActionTypes } from './actions';
-export interface State {
+// State that is required and we have defaults for, before props are passed in
+export interface DefaultState {
network: Network;
- assetBuyer?: AssetBuyer;
assetMetaDataMap: ObjectMap<AssetMetaData>;
- selectedAsset?: Asset;
- availableAssets?: Asset[];
- selectedAssetAmount?: BigNumber;
buyOrderState: OrderState;
- ethUsdPrice?: BigNumber;
- latestBuyQuote?: BuyQuote;
- quoteRequestState: AsyncProcessState;
- latestErrorMessage?: string;
latestErrorDisplayStatus: DisplayStatus;
- affiliateInfo?: AffiliateInfo;
+ quoteRequestState: AsyncProcessState;
}
-export const INITIAL_STATE: State = {
+// State that is required but needs to be derived from the props
+interface PropsDerivedState {
+ providerState: ProviderState;
+}
+
+// State that is optional
+interface OptionalState {
+ selectedAsset: Asset;
+ availableAssets: Asset[];
+ selectedAssetAmount: BigNumber;
+ ethUsdPrice: BigNumber;
+ latestBuyQuote: BuyQuote;
+ latestErrorMessage: string;
+ affiliateInfo: AffiliateInfo;
+}
+
+export type State = DefaultState & PropsDerivedState & Partial<OptionalState>;
+
+export const DEFAULT_STATE: DefaultState = {
network: Network.Mainnet,
- selectedAssetAmount: undefined,
- availableAssets: undefined,
assetMetaDataMap,
- buyOrderState: { processState: OrderProcessState.NONE },
- ethUsdPrice: undefined,
- latestBuyQuote: undefined,
- latestErrorMessage: undefined,
+ buyOrderState: { processState: OrderProcessState.None },
latestErrorDisplayStatus: DisplayStatus.Hidden,
- quoteRequestState: AsyncProcessState.NONE,
- affiliateInfo: undefined,
+ quoteRequestState: AsyncProcessState.None,
};
-export const reducer = (state: State = INITIAL_STATE, action: Action): State => {
- switch (action.type) {
- case ActionTypes.UPDATE_ETH_USD_PRICE:
- return {
- ...state,
- ethUsdPrice: action.data,
- };
- case ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT:
- return {
- ...state,
- selectedAssetAmount: action.data,
- };
- case ActionTypes.UPDATE_LATEST_BUY_QUOTE:
- const newBuyQuoteIfExists = action.data;
- const shouldUpdate =
- _.isUndefined(newBuyQuoteIfExists) || doesBuyQuoteMatchState(newBuyQuoteIfExists, state);
- if (shouldUpdate) {
- return {
- ...state,
- latestBuyQuote: newBuyQuoteIfExists,
- quoteRequestState: AsyncProcessState.SUCCESS,
+export const createReducer = (initialState: State) => {
+ const reducer = (state: State = initialState, action: Action): State => {
+ switch (action.type) {
+ case ActionTypes.SET_ACCOUNT_STATE_LOADING:
+ return reduceStateWithAccount(state, LOADING_ACCOUNT);
+ case ActionTypes.SET_ACCOUNT_STATE_LOCKED:
+ return reduceStateWithAccount(state, LOCKED_ACCOUNT);
+ case ActionTypes.SET_ACCOUNT_STATE_READY: {
+ const account: AccountReady = {
+ state: AccountState.Ready,
+ address: action.data,
};
- } else {
- return state;
+ return reduceStateWithAccount(state, account);
}
-
- case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING:
- return {
- ...state,
- latestBuyQuote: undefined,
- quoteRequestState: AsyncProcessState.PENDING,
- };
- case ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE:
- return {
- ...state,
- latestBuyQuote: undefined,
- quoteRequestState: AsyncProcessState.FAILURE,
- };
- case ActionTypes.SET_BUY_ORDER_STATE_NONE:
- return {
- ...state,
- buyOrderState: { processState: OrderProcessState.NONE },
- };
- case ActionTypes.SET_BUY_ORDER_STATE_VALIDATING:
- return {
- ...state,
- buyOrderState: { processState: OrderProcessState.VALIDATING },
- };
- case ActionTypes.SET_BUY_ORDER_STATE_PROCESSING:
- const processingData = action.data;
- const { startTimeUnix, expectedEndTimeUnix } = processingData;
- return {
- ...state,
- buyOrderState: {
- processState: OrderProcessState.PROCESSING,
- txHash: processingData.txHash,
- progress: {
- startTimeUnix,
- expectedEndTimeUnix,
- },
- },
- };
- case ActionTypes.SET_BUY_ORDER_STATE_FAILURE:
- const failureTxHash = action.data;
- if ('txHash' in state.buyOrderState) {
- if (state.buyOrderState.txHash === failureTxHash) {
- const { txHash, progress } = state.buyOrderState;
- return {
- ...state,
- buyOrderState: {
- processState: OrderProcessState.FAILURE,
- txHash,
- progress,
- },
+ case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: {
+ const { address, ethBalanceInWei } = action.data;
+ const currentAccount = state.providerState.account;
+ if (currentAccount.state !== AccountState.Ready || currentAccount.address !== address) {
+ return state;
+ } else {
+ const newAccount: AccountReady = {
+ ...currentAccount,
+ ethBalanceInWei,
};
+ return reduceStateWithAccount(state, newAccount);
}
}
- return state;
- case ActionTypes.SET_BUY_ORDER_STATE_SUCCESS:
- const successTxHash = action.data;
- if ('txHash' in state.buyOrderState) {
- if (state.buyOrderState.txHash === successTxHash) {
- const { txHash, progress } = state.buyOrderState;
+ case ActionTypes.UPDATE_ETH_USD_PRICE:
+ return {
+ ...state,
+ ethUsdPrice: action.data,
+ };
+ case ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT:
+ return {
+ ...state,
+ selectedAssetAmount: action.data,
+ };
+ case ActionTypes.UPDATE_LATEST_BUY_QUOTE:
+ const newBuyQuoteIfExists = action.data;
+ const shouldUpdate =
+ _.isUndefined(newBuyQuoteIfExists) || doesBuyQuoteMatchState(newBuyQuoteIfExists, state);
+ if (shouldUpdate) {
return {
...state,
- buyOrderState: {
- processState: OrderProcessState.SUCCESS,
- txHash,
- progress,
- },
+ latestBuyQuote: newBuyQuoteIfExists,
+ quoteRequestState: AsyncProcessState.Success,
};
+ } else {
+ return state;
}
- }
- return state;
- case ActionTypes.SET_ERROR_MESSAGE:
- return {
- ...state,
- latestErrorMessage: action.data,
- latestErrorDisplayStatus: DisplayStatus.Present,
- };
- case ActionTypes.HIDE_ERROR:
- return {
- ...state,
- latestErrorDisplayStatus: DisplayStatus.Hidden,
- };
- case ActionTypes.CLEAR_ERROR:
- return {
- ...state,
- latestErrorMessage: undefined,
- latestErrorDisplayStatus: DisplayStatus.Hidden,
- };
- case ActionTypes.UPDATE_SELECTED_ASSET:
- return {
- ...state,
- selectedAsset: action.data,
- };
- case ActionTypes.RESET_AMOUNT:
- return {
- ...state,
- latestBuyQuote: undefined,
- quoteRequestState: AsyncProcessState.NONE,
- buyOrderState: { processState: OrderProcessState.NONE },
- selectedAssetAmount: undefined,
- };
- case ActionTypes.SET_AVAILABLE_ASSETS:
- return {
- ...state,
- availableAssets: action.data,
- };
- default:
- return state;
- }
+ case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING:
+ return {
+ ...state,
+ latestBuyQuote: undefined,
+ quoteRequestState: AsyncProcessState.Pending,
+ };
+ case ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE:
+ return {
+ ...state,
+ latestBuyQuote: undefined,
+ quoteRequestState: AsyncProcessState.Failure,
+ };
+ case ActionTypes.SET_BUY_ORDER_STATE_NONE:
+ return {
+ ...state,
+ buyOrderState: { processState: OrderProcessState.None },
+ };
+ case ActionTypes.SET_BUY_ORDER_STATE_VALIDATING:
+ return {
+ ...state,
+ buyOrderState: { processState: OrderProcessState.Validating },
+ };
+ case ActionTypes.SET_BUY_ORDER_STATE_PROCESSING:
+ const processingData = action.data;
+ const { startTimeUnix, expectedEndTimeUnix } = processingData;
+ return {
+ ...state,
+ buyOrderState: {
+ processState: OrderProcessState.Processing,
+ txHash: processingData.txHash,
+ progress: {
+ startTimeUnix,
+ expectedEndTimeUnix,
+ },
+ },
+ };
+ case ActionTypes.SET_BUY_ORDER_STATE_FAILURE:
+ const failureTxHash = action.data;
+ if ('txHash' in state.buyOrderState) {
+ if (state.buyOrderState.txHash === failureTxHash) {
+ const { txHash, progress } = state.buyOrderState;
+ return {
+ ...state,
+ buyOrderState: {
+ processState: OrderProcessState.Failure,
+ txHash,
+ progress,
+ },
+ };
+ }
+ }
+ return state;
+ case ActionTypes.SET_BUY_ORDER_STATE_SUCCESS:
+ const successTxHash = action.data;
+ if ('txHash' in state.buyOrderState) {
+ if (state.buyOrderState.txHash === successTxHash) {
+ const { txHash, progress } = state.buyOrderState;
+ return {
+ ...state,
+ buyOrderState: {
+ processState: OrderProcessState.Success,
+ txHash,
+ progress,
+ },
+ };
+ }
+ }
+ return state;
+ case ActionTypes.SET_ERROR_MESSAGE:
+ return {
+ ...state,
+ latestErrorMessage: action.data,
+ latestErrorDisplayStatus: DisplayStatus.Present,
+ };
+ case ActionTypes.HIDE_ERROR:
+ return {
+ ...state,
+ latestErrorDisplayStatus: DisplayStatus.Hidden,
+ };
+ case ActionTypes.CLEAR_ERROR:
+ return {
+ ...state,
+ latestErrorMessage: undefined,
+ latestErrorDisplayStatus: DisplayStatus.Hidden,
+ };
+ case ActionTypes.UPDATE_SELECTED_ASSET:
+ return {
+ ...state,
+ selectedAsset: action.data,
+ };
+ case ActionTypes.RESET_AMOUNT:
+ return {
+ ...state,
+ latestBuyQuote: undefined,
+ quoteRequestState: AsyncProcessState.None,
+ buyOrderState: { processState: OrderProcessState.None },
+ selectedAssetAmount: undefined,
+ };
+ case ActionTypes.SET_AVAILABLE_ASSETS:
+ return {
+ ...state,
+ availableAssets: action.data,
+ };
+ default:
+ return state;
+ }
+ };
+ return reducer;
+};
+
+const reduceStateWithAccount = (state: State, account: Account) => {
+ const oldProviderState = state.providerState;
+ const newProviderState: ProviderState = {
+ ...oldProviderState,
+ account,
+ };
+ return {
+ ...state,
+ providerState: newProviderState,
+ };
};
const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => {
diff --git a/packages/instant/src/redux/store.ts b/packages/instant/src/redux/store.ts
index 01deb8690..20710765d 100644
--- a/packages/instant/src/redux/store.ts
+++ b/packages/instant/src/redux/store.ts
@@ -2,12 +2,13 @@ import * as _ from 'lodash';
import { createStore, Store as ReduxStore } from 'redux';
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
-import { reducer, State } from './reducer';
+import { createReducer, State } from './reducer';
export type Store = ReduxStore<State>;
export const store = {
- create: (state: State): Store => {
- return createStore(reducer, state, devToolsEnhancer({}));
+ create: (initialState: State): Store => {
+ const reducer = createReducer(initialState);
+ return createStore(reducer, initialState, devToolsEnhancer({}));
},
};
diff --git a/packages/instant/src/style/media.ts b/packages/instant/src/style/media.ts
new file mode 100644
index 000000000..bbf376694
--- /dev/null
+++ b/packages/instant/src/style/media.ts
@@ -0,0 +1,51 @@
+import { InterpolationValue } from 'styled-components';
+
+import { css } from './theme';
+
+export enum ScreenWidths {
+ Sm = 40,
+ Md = 52,
+ Lg = 64,
+}
+
+export const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) => css`
+ @media (max-width: ${screenWidth}em) {
+ ${css.apply(css, args)};
+ }
+`;
+
+export const media = {
+ small: generateMediaWrapper(ScreenWidths.Sm),
+ medium: generateMediaWrapper(ScreenWidths.Md),
+ large: generateMediaWrapper(ScreenWidths.Lg),
+};
+
+export interface ScreenSpecification<T> {
+ default: T;
+ sm?: T;
+ md?: T;
+ lg?: T;
+}
+export type OptionallyScreenSpecific<T> = T | ScreenSpecification<T>;
+export type MediaChoice = OptionallyScreenSpecific<string>;
+/**
+ * Given a css property name and a OptionallyScreenSpecific value,
+ * generates css properties with screen-specific viewport styling
+ */
+export function stylesForMedia<T extends string | number>(
+ cssPropertyName: string,
+ choice: OptionallyScreenSpecific<T>,
+): InterpolationValue[] {
+ if (typeof choice === 'object') {
+ return css`
+ ${cssPropertyName}: ${choice.default};
+ ${choice.lg && media.large`${cssPropertyName}: ${choice.lg}`}
+ ${choice.md && media.medium`${cssPropertyName}: ${choice.md}`}
+ ${choice.sm && media.small`${cssPropertyName}: ${choice.sm}`}
+ `;
+ } else {
+ return css`
+ ${cssPropertyName}: ${choice};
+ `;
+ }
+}
diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts
index d10c9b72c..1e9f55e00 100644
--- a/packages/instant/src/style/theme.ts
+++ b/packages/instant/src/style/theme.ts
@@ -1,6 +1,6 @@
import * as styledComponents from 'styled-components';
-const { default: styled, css, keyframes, withTheme, ThemeProvider } = styledComponents;
+const { default: styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider } = styledComponents;
export type Theme = { [key in ColorOption]: string };
@@ -15,6 +15,8 @@ export enum ColorOption {
white = 'white',
lightOrange = 'lightOrange',
darkOrange = 'darkOrange',
+ green = 'green',
+ red = 'red',
}
export const theme: Theme = {
@@ -28,9 +30,15 @@ export const theme: Theme = {
white: 'white',
lightOrange: '#F9F2ED',
darkOrange: '#F2994C',
+ green: '#3CB34F',
+ red: '#D00000',
};
export const transparentWhite = 'rgba(255,255,255,0.3)';
-export const overlayBlack = 'rgba(0, 0, 0, 0.6)';
+export const completelyTransparent = 'rga(0, 0, 0, 0)';
-export { styled, css, keyframes, withTheme, ThemeProvider };
+export const generateOverlayBlack = (opacity = 0.6) => {
+ return `rgba(0, 0, 0, ${opacity})`;
+};
+
+export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider };
diff --git a/packages/instant/src/style/z_index.ts b/packages/instant/src/style/z_index.ts
index 727a5189d..ba2d27a17 100644
--- a/packages/instant/src/style/z_index.ts
+++ b/packages/instant/src/style/z_index.ts
@@ -1,5 +1,9 @@
export const zIndex = {
- errorPopup: 1,
- mainContainer: 2,
- panel: 3,
+ errorPopBehind: 10,
+ mainContainer: 20,
+ dropdownItems: 30,
+ panel: 40,
+ containerOverlay: 45,
+ errorPopup: 50,
+ overlayDefault: 100,
};
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index 449bc0f31..b43a82d46 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -1,20 +1,24 @@
-import { AssetProxyId, ObjectMap } from '@0x/types';
+import { AssetBuyer, BigNumber } from '@0x/asset-buyer';
+import { AssetProxyId, ObjectMap, SignedOrder } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { Provider } from 'ethereum-types';
// Reusable
+export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
export type Maybe<T> = T | undefined;
export enum AsyncProcessState {
- NONE = 'None',
- PENDING = 'Pending',
- SUCCESS = 'Success',
- FAILURE = 'Failure',
+ None = 'NONE',
+ Pending = 'PENDING',
+ Success = 'SUCCESS',
+ Failure = 'FAILURE',
}
export enum OrderProcessState {
- NONE = 'None',
- VALIDATING = 'Validating',
- PROCESSING = 'Processing',
- SUCCESS = 'Success',
- FAILURE = 'Failure',
+ None = 'NONE',
+ Validating = 'VALIDATING',
+ Processing = 'PROCESSING',
+ Success = 'SUCCESS',
+ Failure = 'FAILURE',
}
export interface SimulatedProgress {
@@ -23,10 +27,10 @@ export interface SimulatedProgress {
}
interface OrderStatePreTx {
- processState: OrderProcessState.NONE | OrderProcessState.VALIDATING;
+ processState: OrderProcessState.None | OrderProcessState.Validating;
}
interface OrderStatePostTx {
- processState: OrderProcessState.PROCESSING | OrderProcessState.SUCCESS | OrderProcessState.FAILURE;
+ processState: OrderProcessState.Processing | OrderProcessState.Success | OrderProcessState.Failure;
txHash: string;
progress: SimulatedProgress;
}
@@ -89,3 +93,35 @@ export interface AffiliateInfo {
feeRecipient: string;
feePercentage: number;
}
+
+export interface ProviderState {
+ provider: Provider;
+ assetBuyer: AssetBuyer;
+ web3Wrapper: Web3Wrapper;
+ account: Account;
+}
+
+export enum AccountState {
+ None = 'NONE,',
+ Loading = 'LOADING',
+ Ready = 'READY',
+ Locked = 'LOCKED',
+}
+
+export interface AccountReady {
+ state: AccountState.Ready;
+ address: string;
+ ethBalanceInWei?: BigNumber;
+}
+export interface AccountNotReady {
+ state: AccountState.None | AccountState.Loading | AccountState.Locked;
+}
+
+export type Account = AccountReady | AccountNotReady;
+
+export type OrderSource = string | SignedOrder[];
+
+export interface AddressAndEthBalanceInWei {
+ address: string;
+ ethBalanceInWei: BigNumber;
+}
diff --git a/packages/instant/src/util/asset_buyer_factory.ts b/packages/instant/src/util/asset_buyer_factory.ts
new file mode 100644
index 000000000..5ba46223c
--- /dev/null
+++ b/packages/instant/src/util/asset_buyer_factory.ts
@@ -0,0 +1,17 @@
+import { AssetBuyer, AssetBuyerOpts } from '@0x/asset-buyer';
+import { Provider } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { Network, OrderSource } from '../types';
+
+export const assetBuyerFactory = {
+ getAssetBuyer: (provider: Provider, orderSource: OrderSource, network: Network): AssetBuyer => {
+ const assetBuyerOptions: Partial<AssetBuyerOpts> = {
+ networkId: network,
+ };
+ const assetBuyer = _.isString(orderSource)
+ ? AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(provider, orderSource, assetBuyerOptions)
+ : AssetBuyer.getAssetBuyerForProvidedOrders(provider, orderSource, assetBuyerOptions);
+ return assetBuyer;
+ },
+};
diff --git a/packages/instant/src/util/balance.ts b/packages/instant/src/util/balance.ts
deleted file mode 100644
index f2271495b..000000000
--- a/packages/instant/src/util/balance.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { BuyQuote } from '@0x/asset-buyer';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-
-export const balanceUtil = {
- hasSufficientEth: async (takerAddress: string | undefined, buyQuote: BuyQuote, web3Wrapper: Web3Wrapper) => {
- if (_.isUndefined(takerAddress)) {
- return false;
- }
- const balanceWei = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- return balanceWei.gte(buyQuote.worstCaseQuoteInfo.totalEthAmount);
- },
-};
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
new file mode 100644
index 000000000..c33e28f1c
--- /dev/null
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -0,0 +1,59 @@
+import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as _ from 'lodash';
+import { Dispatch } from 'redux';
+import { oc } from 'ts-optchain';
+
+import { Action, actions } from '../redux/actions';
+import { AffiliateInfo, ERC20Asset } from '../types';
+import { assetUtils } from '../util/asset';
+import { errorFlasher } from '../util/error_flasher';
+
+export const buyQuoteUpdater = {
+ updateBuyQuoteAsync: async (
+ assetBuyer: AssetBuyer,
+ dispatch: Dispatch<Action>,
+ asset: ERC20Asset,
+ assetAmount: BigNumber,
+ setPending = true,
+ affiliateInfo?: AffiliateInfo,
+ ): Promise<void> => {
+ // get a new buy quote.
+ const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals);
+ if (setPending) {
+ // mark quote as pending
+ dispatch(actions.setQuoteRequestStatePending());
+ }
+ const feePercentage = oc(affiliateInfo).feePercentage();
+ let newBuyQuote: BuyQuote | undefined;
+ try {
+ newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
+ } catch (error) {
+ dispatch(actions.setQuoteRequestStateFailure());
+ let errorMessage;
+ if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
+ const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
+ errorMessage = `Not enough ${assetName} available`;
+ } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
+ errorMessage = 'Not enough ZRX available';
+ } else if (
+ error.message === AssetBuyerError.StandardRelayerApiError ||
+ error.message.startsWith(AssetBuyerError.AssetUnavailable)
+ ) {
+ const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
+ errorMessage = `${assetName} is currently unavailable`;
+ }
+ if (!_.isUndefined(errorMessage)) {
+ errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
+ } else {
+ throw error;
+ }
+ return;
+ }
+ // We have a successful new buy quote
+ errorFlasher.clearError(dispatch);
+ // invalidate the last buy quote.
+ dispatch(actions.updateLatestBuyQuote(newBuyQuote));
+ },
+};
diff --git a/packages/instant/src/util/etherscan.ts b/packages/instant/src/util/etherscan.ts
index cfc2578a3..4d62c4d9f 100644
--- a/packages/instant/src/util/etherscan.ts
+++ b/packages/instant/src/util/etherscan.ts
@@ -21,4 +21,11 @@ export const etherscanUtil = {
}
return `https://${prefix}etherscan.io/tx/${txHash}`;
},
+ getEtherScanEthAddressIfExists: (ethAddress: string, networkId: number) => {
+ const prefix = etherscanPrefix(networkId);
+ if (_.isUndefined(prefix)) {
+ return;
+ }
+ return `https://${prefix}etherscan.io/address/${ethAddress}`;
+ },
};
diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts
index 4a48dec9d..44661d697 100644
--- a/packages/instant/src/util/format.ts
+++ b/packages/instant/src/util/format.ts
@@ -50,4 +50,7 @@ export const format = {
}
return `$${ethUnitAmount.mul(ethUsdPrice).toFixed(decimalPlaces)}`;
},
+ ethAddress: (address: string): string => {
+ return `0x${address.slice(2, 7)}…${address.slice(-5)}`;
+ },
};
diff --git a/packages/instant/src/util/heartbeater.ts b/packages/instant/src/util/heartbeater.ts
new file mode 100644
index 000000000..e700d489e
--- /dev/null
+++ b/packages/instant/src/util/heartbeater.ts
@@ -0,0 +1,35 @@
+import { intervalUtils } from '@0x/utils';
+import * as _ from 'lodash';
+
+type HeartbeatableFunction = () => Promise<void>;
+export class Heartbeater {
+ private _intervalId?: NodeJS.Timer;
+ private readonly _performImmediatelyOnStart: boolean;
+ private readonly _performFunction: HeartbeatableFunction;
+
+ public constructor(performingFunctionAsync: HeartbeatableFunction, performImmediatelyOnStart: boolean) {
+ this._performFunction = performingFunctionAsync;
+ this._performImmediatelyOnStart = performImmediatelyOnStart;
+ }
+
+ public start(intervalTimeMs: number): void {
+ if (!_.isUndefined(this._intervalId)) {
+ throw new Error('Heartbeat is running, please stop before restarting');
+ }
+
+ if (this._performImmediatelyOnStart) {
+ // tslint:disable-next-line:no-floating-promises
+ this._performFunction();
+ }
+
+ // tslint:disable-next-line:no-unbound-method
+ this._intervalId = intervalUtils.setAsyncExcludingInterval(this._performFunction, intervalTimeMs, _.noop);
+ }
+
+ public stop(): void {
+ if (this._intervalId) {
+ intervalUtils.clearInterval(this._intervalId);
+ }
+ this._intervalId = undefined;
+ }
+}
diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts
new file mode 100644
index 000000000..96a8ac4e6
--- /dev/null
+++ b/packages/instant/src/util/heartbeater_factory.ts
@@ -0,0 +1,22 @@
+import { asyncData } from '../redux/async_data';
+import { Store } from '../redux/store';
+
+import { Heartbeater } from './heartbeater';
+
+export interface HeartbeatFactoryOptions {
+ store: Store;
+ shouldPerformImmediatelyOnStart: boolean;
+}
+export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
+ const { store, shouldPerformImmediatelyOnStart } = options;
+ return new Heartbeater(async () => {
+ await asyncData.fetchAccountInfoAndDispatchToStore({ store, shouldSetToLoading: false });
+ }, shouldPerformImmediatelyOnStart);
+};
+
+export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
+ const { store, shouldPerformImmediatelyOnStart } = options;
+ return new Heartbeater(async () => {
+ await asyncData.fetchCurrentBuyQuoteAndDispatchToStore({ store, shouldSetPending: false });
+ }, shouldPerformImmediatelyOnStart);
+};
diff --git a/packages/instant/src/util/injected_provider.ts b/packages/instant/src/util/injected_provider.ts
deleted file mode 100644
index 40f9e2da5..000000000
--- a/packages/instant/src/util/injected_provider.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Provider } from 'ethereum-types';
-import * as _ from 'lodash';
-
-export const getInjectedProvider = (): Provider => {
- const injectedProviderIfExists = (window as any).ethereum;
- if (!_.isUndefined(injectedProviderIfExists)) {
- // TODO: call enable here when implementing wallet connection flow
- return injectedProviderIfExists;
- }
- const injectedWeb3IfExists = (window as any).web3;
- if (!_.isUndefined(injectedWeb3IfExists.currentProvider)) {
- return injectedWeb3IfExists.currentProvider;
- } else {
- throw new Error(`No injected web3 found`);
- }
-};
diff --git a/packages/instant/src/util/provider_factory.ts b/packages/instant/src/util/provider_factory.ts
new file mode 100644
index 000000000..603f7674d
--- /dev/null
+++ b/packages/instant/src/util/provider_factory.ts
@@ -0,0 +1,34 @@
+import { EmptyWalletSubprovider, RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders';
+import { Provider } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { BLOCK_POLLING_INTERVAL_MS, ETHEREUM_NODE_URL_BY_NETWORK } from '../constants';
+import { Maybe, Network } from '../types';
+
+export const providerFactory = {
+ getInjectedProviderIfExists: (): Maybe<Provider> => {
+ const injectedProviderIfExists = (window as any).ethereum;
+ if (!_.isUndefined(injectedProviderIfExists)) {
+ return injectedProviderIfExists;
+ }
+ const injectedWeb3IfExists = (window as any).web3;
+ if (!_.isUndefined(injectedWeb3IfExists) && !_.isUndefined(injectedWeb3IfExists.currentProvider)) {
+ return injectedWeb3IfExists.currentProvider;
+ }
+ return undefined;
+ },
+ getFallbackNoSigningProvider: (network: Network): Provider => {
+ const providerEngine = new Web3ProviderEngine({
+ pollingInterval: BLOCK_POLLING_INTERVAL_MS,
+ });
+ // Intercept calls to `eth_accounts` and always return empty
+ providerEngine.addProvider(new EmptyWalletSubprovider());
+ // Construct an RPC subprovider, all data based requests will be sent via the RPCSubprovider
+ // TODO(bmillman): make this more resilient to infura failures
+ const rpcUrl = ETHEREUM_NODE_URL_BY_NETWORK[network];
+ providerEngine.addProvider(new RPCSubprovider(rpcUrl));
+ // // Start the Provider Engine
+ providerEngine.start();
+ return providerEngine;
+ },
+};
diff --git a/packages/instant/src/util/provider_state_factory.ts b/packages/instant/src/util/provider_state_factory.ts
new file mode 100644
index 000000000..3281f6bfb
--- /dev/null
+++ b/packages/instant/src/util/provider_state_factory.ts
@@ -0,0 +1,63 @@
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { Provider } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { LOADING_ACCOUNT, NO_ACCOUNT } from '../constants';
+import { Maybe, Network, OrderSource, ProviderState } from '../types';
+
+import { assetBuyerFactory } from './asset_buyer_factory';
+import { providerFactory } from './provider_factory';
+
+export const providerStateFactory = {
+ getInitialProviderState: (orderSource: OrderSource, network: Network, provider?: Provider): ProviderState => {
+ if (!_.isUndefined(provider)) {
+ return providerStateFactory.getInitialProviderStateFromProvider(orderSource, network, provider);
+ }
+ const providerStateFromWindowIfExits = providerStateFactory.getInitialProviderStateFromWindowIfExists(
+ orderSource,
+ network,
+ );
+ if (providerStateFromWindowIfExits) {
+ return providerStateFromWindowIfExits;
+ } else {
+ return providerStateFactory.getInitialProviderStateFallback(orderSource, network);
+ }
+ },
+ getInitialProviderStateFromProvider: (
+ orderSource: OrderSource,
+ network: Network,
+ provider: Provider,
+ ): ProviderState => {
+ const providerState: ProviderState = {
+ provider,
+ web3Wrapper: new Web3Wrapper(provider),
+ assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network),
+ account: LOADING_ACCOUNT,
+ };
+ return providerState;
+ },
+ getInitialProviderStateFromWindowIfExists: (orderSource: OrderSource, network: Network): Maybe<ProviderState> => {
+ const injectedProviderIfExists = providerFactory.getInjectedProviderIfExists();
+ if (!_.isUndefined(injectedProviderIfExists)) {
+ const providerState: ProviderState = {
+ provider: injectedProviderIfExists,
+ web3Wrapper: new Web3Wrapper(injectedProviderIfExists),
+ assetBuyer: assetBuyerFactory.getAssetBuyer(injectedProviderIfExists, orderSource, network),
+ account: LOADING_ACCOUNT,
+ };
+ return providerState;
+ } else {
+ return undefined;
+ }
+ },
+ getInitialProviderStateFallback: (orderSource: OrderSource, network: Network): ProviderState => {
+ const provider = providerFactory.getFallbackNoSigningProvider(network);
+ const providerState: ProviderState = {
+ provider,
+ web3Wrapper: new Web3Wrapper(provider),
+ assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network),
+ account: NO_ACCOUNT,
+ };
+ return providerState;
+ },
+};
diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json
index ae1369ca7..c273c09af 100644
--- a/packages/json-schemas/CHANGELOG.json
+++ b/packages/json-schemas/CHANGELOG.json
@@ -11,7 +11,8 @@
"note": "Add schemas from @0x/connect",
"pr": 1250
}
- ]
+ ],
+ "timestamp": 1541740904
},
{
"version": "2.0.0",
diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md
index 21efe1be0..a1c784640 100644
--- a/packages/json-schemas/CHANGELOG.md
+++ b/packages/json-schemas/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.1 - _November 9, 2018_
+
+ * Improve schemas by enforcing that amounts that must be whole numbers (e.g Order asset amounts) no longer allow decimal amounts (#1173)
+
## v2.0.0 - _October 18, 2018_
* Convert all schemas to JSON files so that they can be used with `json-schema` implemenations in other programming languages. (#1145)
diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json
index 57715c601..c87cbb65a 100644
--- a/packages/json-schemas/package.json
+++ b/packages/json-schemas/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/json-schemas",
- "version": "2.0.0",
+ "version": "2.0.1",
"engines": {
"node": ">=6.12"
},
@@ -39,14 +39,14 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/json-schemas/README.md",
"dependencies": {
- "@0x/typescript-typings": "^3.0.3",
+ "@0x/typescript-typings": "^3.0.4",
"@types/node": "*",
"jsonschema": "^1.2.0",
"lodash.values": "^4.3.0"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
- "@0x/utils": "^2.0.3",
+ "@0x/tslint-config": "^1.0.10",
+ "@0x/utils": "^2.0.4",
"@types/lodash.foreach": "^4.5.3",
"@types/lodash.values": "^4.3.3",
"@types/mocha": "^2.2.42",
diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json
index e3432c010..35a0834f2 100644
--- a/packages/metacoin/package.json
+++ b/packages/metacoin/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/metacoin",
- "version": "0.0.24",
+ "version": "0.0.25",
"engines": {
"node": ">=6.12"
},
@@ -29,25 +29,25 @@
"author": "",
"license": "Apache-2.0",
"dependencies": {
- "@0x/abi-gen": "^1.0.14",
- "@0x/base-contract": "^3.0.2",
- "@0x/sol-cov": "^2.1.8",
- "@0x/subproviders": "^2.1.0",
- "@0x/tslint-config": "^1.0.9",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/abi-gen": "^1.0.15",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/sol-cov": "^2.1.9",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/tslint-config": "^1.0.10",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/mocha": "^5.2.2",
"copyfiles": "^2.0.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5",
"run-s": "^0.0.0"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/sol-compiler": "^1.1.8",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/sol-compiler": "^1.1.9",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json
index 6d93feb1e..b7128f8e1 100644
--- a/packages/migrations/CHANGELOG.json
+++ b/packages/migrations/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.0.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "2.0.0",
"changes": [
{
diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md
index 8d3346972..387ae0abb 100644
--- a/packages/migrations/CHANGELOG.md
+++ b/packages/migrations/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.1 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.0.0 - _October 18, 2018_
* Contract artifacts have been moved to the new @0xproject/contract-artifacts package. v1 migrations have been removed. `runMigrationsAsync` returns the addresses of the contracts that were deployed. (#1105)
diff --git a/packages/migrations/package.json b/packages/migrations/package.json
index b610d3c6a..d8c5fb6c2 100644
--- a/packages/migrations/package.json
+++ b/packages/migrations/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/migrations",
- "version": "2.0.0",
+ "version": "2.0.1",
"engines": {
"node": ">=6.12"
},
@@ -17,9 +17,9 @@
},
"license": "Apache-2.0",
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/tslint-config": "^1.0.9",
- "@0x/types": "^1.2.0",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/tslint-config": "^1.0.10",
+ "@0x/types": "^1.2.1",
"@types/yargs": "^10.0.0",
"make-promises-safe": "^1.1.0",
"npm-run-all": "^4.1.2",
@@ -29,18 +29,18 @@
"yargs": "^10.0.3"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.0.1",
- "@0x/base-contract": "^3.0.2",
- "@0x/contract-addresses": "^1.0.1",
- "@0x/contract-artifacts": "^1.0.1",
- "@0x/order-utils": "^2.0.0",
- "@0x/sol-compiler": "^1.1.8",
- "@0x/subproviders": "^2.1.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/abi-gen-wrappers": "^1.0.2",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/contract-addresses": "^1.1.0",
+ "@0x/contract-artifacts": "^1.1.0",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/sol-compiler": "^1.1.9",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@ledgerhq/hw-app-eth": "^4.3.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
},
diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json
index a83f90516..a31085014 100644
--- a/packages/monorepo-scripts/package.json
+++ b/packages/monorepo-scripts/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@0x/monorepo-scripts",
- "version": "1.0.12",
+ "version": "1.0.13",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json
index 22af2412b..0ed6117df 100644
--- a/packages/order-utils/CHANGELOG.json
+++ b/packages/order-utils/CHANGELOG.json
@@ -1,5 +1,39 @@
[
{
+ "version": "3.0.0",
+ "changes": [
+ {
+ "note":
+ "Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync`",
+ "pr": 1235
+ },
+ {
+ "note":
+ "Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive",
+ "pr": 1235
+ },
+ {
+ "note":
+ "Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218)",
+ "pr": 1235
+ },
+ {
+ "note":
+ "Modified the `AbstractOrderFilledCancelledFetcher` interface slightly such that `isOrderCancelledAsync` accepts a `signedOrder` instead of an `orderHash` param",
+ "pr": 1235
+ }
+ ]
+ },
+ {
+ "version": "2.0.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "2.0.0",
"changes": [
{
diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md
index afd5c4adc..31bd02595 100644
--- a/packages/order-utils/CHANGELOG.md
+++ b/packages/order-utils/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.1 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.0.0 - _October 18, 2018_
* Added `ecSignOrderAsync` to first sign an order using `eth_signTypedData` and fallback to `eth_sign`. (#1102)
diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json
index a6a84b940..d6fb9892e 100644
--- a/packages/order-utils/package.json
+++ b/packages/order-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/order-utils",
- "version": "2.0.0",
+ "version": "2.0.1",
"engines": {
"node": ">=6.12"
},
@@ -35,8 +35,8 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md",
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/tslint-config": "^1.0.10",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"chai": "^4.0.1",
@@ -53,18 +53,18 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.0.1",
- "@0x/assert": "^1.0.14",
- "@0x/base-contract": "^3.0.2",
- "@0x/contract-artifacts": "^1.0.1",
- "@0x/json-schemas": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/abi-gen-wrappers": "^1.0.2",
+ "@0x/assert": "^1.0.15",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/contract-artifacts": "^1.1.0",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/node": "*",
"bn.js": "^4.11.8",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1",
"ethers": "~4.0.4",
diff --git a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts b/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts
index de096b7d9..9e240f9ef 100644
--- a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts
+++ b/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts
@@ -1,3 +1,4 @@
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
/**
@@ -17,6 +18,6 @@ export abstract class AbstractOrderFilledCancelledFetcher {
* @param orderHash OrderHash of order we are interested in
* @return Whether or not the order is cancelled
*/
- public abstract async isOrderCancelledAsync(orderHash: string): Promise<boolean>;
+ public abstract async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean>;
public abstract getZRXAssetData(): string;
}
diff --git a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts b/packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts
index d9e66db06..186521401 100644
--- a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts
+++ b/packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts
@@ -1,8 +1,9 @@
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
export abstract class AbstractOrderFilledCancelledLazyStore {
public abstract async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
- public abstract async getIsCancelledAsync(orderHash: string): Promise<boolean>;
+ public abstract async getIsCancelledAsync(signedOrder: SignedOrder): Promise<boolean>;
public abstract setFilledTakerAmount(orderHash: string, balance: BigNumber): void;
public abstract deleteFilledTakerAmount(orderHash: string): void;
public abstract setIsCancelled(orderHash: string, isCancelled: boolean): void;
diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts
index 159aeeb09..fe0d6c773 100644
--- a/packages/order-utils/src/order_state_utils.ts
+++ b/packages/order-utils/src/order_state_utils.ts
@@ -117,7 +117,7 @@ export class OrderStateUtils {
public async getOpenOrderStateAsync(signedOrder: SignedOrder, transactionHash?: string): Promise<OrderState> {
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
+ const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder);
const sidedOrderRelevantState = {
isMakerSide: true,
traderBalance: orderRelevantState.makerBalance,
@@ -256,7 +256,7 @@ export class OrderStateUtils {
const filledTakerAssetAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
const totalMakerAssetAmount = signedOrder.makerAssetAmount;
const totalTakerAssetAmount = signedOrder.takerAssetAmount;
- const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
+ const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder);
const remainingTakerAssetAmount = isOrderCancelled
? new BigNumber(0)
: totalTakerAssetAmount.minus(filledTakerAssetAmount);
diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts
index a40069f63..ae4291ea8 100644
--- a/packages/order-utils/src/order_validation_utils.ts
+++ b/packages/order-utils/src/order_validation_utils.ts
@@ -1,4 +1,4 @@
-import { RevertReason, SignedOrder } from '@0x/types';
+import { ExchangeContractErrs, RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
@@ -17,6 +17,7 @@ import { utils } from './utils';
*/
export class OrderValidationUtils {
private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher;
+ private readonly _provider: Provider;
/**
* A Typescript implementation mirroring the implementation of isRoundingError in the
* Exchange smart contract
@@ -57,65 +58,53 @@ export class OrderValidationUtils {
senderAddress: string,
zrxAssetData: string,
): Promise<void> {
- try {
- const fillMakerTokenAmount = utils.getPartialAmountFloor(
- fillTakerAssetAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerAssetAmount,
- );
- await exchangeTradeEmulator.transferFromAsync(
- signedOrder.makerAssetData,
- signedOrder.makerAddress,
- senderAddress,
- fillMakerTokenAmount,
- TradeSide.Maker,
- TransferType.Trade,
- );
- await exchangeTradeEmulator.transferFromAsync(
- signedOrder.takerAssetData,
- senderAddress,
- signedOrder.makerAddress,
- fillTakerAssetAmount,
- TradeSide.Taker,
- TransferType.Trade,
- );
- const makerFeeAmount = utils.getPartialAmountFloor(
- fillTakerAssetAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerFee,
- );
- await exchangeTradeEmulator.transferFromAsync(
- zrxAssetData,
- signedOrder.makerAddress,
- signedOrder.feeRecipientAddress,
- makerFeeAmount,
- TradeSide.Maker,
- TransferType.Fee,
- );
- const takerFeeAmount = utils.getPartialAmountFloor(
- fillTakerAssetAmount,
- signedOrder.takerAssetAmount,
- signedOrder.takerFee,
- );
- await exchangeTradeEmulator.transferFromAsync(
- zrxAssetData,
- senderAddress,
- signedOrder.feeRecipientAddress,
- takerFeeAmount,
- TradeSide.Taker,
- TransferType.Fee,
- );
- } catch (err) {
- throw new Error(RevertReason.TransferFailed);
- }
- }
- private static _validateRemainingFillAmountNotZeroOrThrow(
- takerAssetAmount: BigNumber,
- filledTakerTokenAmount: BigNumber,
- ): void {
- if (takerAssetAmount.eq(filledTakerTokenAmount)) {
- throw new Error(RevertReason.OrderUnfillable);
- }
+ const fillMakerTokenAmount = utils.getPartialAmountFloor(
+ fillTakerAssetAmount,
+ signedOrder.takerAssetAmount,
+ signedOrder.makerAssetAmount,
+ );
+ await exchangeTradeEmulator.transferFromAsync(
+ signedOrder.makerAssetData,
+ signedOrder.makerAddress,
+ senderAddress,
+ fillMakerTokenAmount,
+ TradeSide.Maker,
+ TransferType.Trade,
+ );
+ await exchangeTradeEmulator.transferFromAsync(
+ signedOrder.takerAssetData,
+ senderAddress,
+ signedOrder.makerAddress,
+ fillTakerAssetAmount,
+ TradeSide.Taker,
+ TransferType.Trade,
+ );
+ const makerFeeAmount = utils.getPartialAmountFloor(
+ fillTakerAssetAmount,
+ signedOrder.takerAssetAmount,
+ signedOrder.makerFee,
+ );
+ await exchangeTradeEmulator.transferFromAsync(
+ zrxAssetData,
+ signedOrder.makerAddress,
+ signedOrder.feeRecipientAddress,
+ makerFeeAmount,
+ TradeSide.Maker,
+ TransferType.Fee,
+ );
+ const takerFeeAmount = utils.getPartialAmountFloor(
+ fillTakerAssetAmount,
+ signedOrder.takerAssetAmount,
+ signedOrder.takerFee,
+ );
+ await exchangeTradeEmulator.transferFromAsync(
+ zrxAssetData,
+ senderAddress,
+ signedOrder.feeRecipientAddress,
+ takerFeeAmount,
+ TradeSide.Taker,
+ TransferType.Fee,
+ );
}
private static _validateOrderNotExpiredOrThrow(expirationTimeSeconds: BigNumber): void {
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
@@ -128,9 +117,13 @@ export class OrderValidationUtils {
* @param orderFilledCancelledFetcher A module that implements the AbstractOrderFilledCancelledFetcher
* @return An instance of OrderValidationUtils
*/
- constructor(orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher) {
+ constructor(orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher, provider: Provider) {
this._orderFilledCancelledFetcher = orderFilledCancelledFetcher;
+ this._provider = provider;
}
+ // TODO(fabio): remove this method once the smart contracts have been refactored
+ // to return helpful revert reasons instead of ORDER_UNFILLABLE. Instruct devs
+ // to make "calls" to validate order fillability + getOrderInfo for fillable amount.
/**
* Validate if the supplied order is fillable, and throw if it isn't
* @param exchangeTradeEmulator ExchangeTradeEmulator instance
@@ -146,12 +139,29 @@ export class OrderValidationUtils {
expectedFillTakerTokenAmount?: BigNumber,
): Promise<void> {
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
- OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
- signedOrder.takerAssetAmount,
- filledTakerTokenAmount,
+ const isValidSignature = await signatureUtils.isValidSignatureAsync(
+ this._provider,
+ orderHash,
+ signedOrder.signature,
+ signedOrder.makerAddress,
);
- OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationTimeSeconds);
+ if (!isValidSignature) {
+ throw new Error(RevertReason.InvalidOrderSignature);
+ }
+
+ const isCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder);
+ if (isCancelled) {
+ throw new Error('CANCELLED');
+ }
+ const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
+ if (signedOrder.takerAssetAmount.eq(filledTakerTokenAmount)) {
+ throw new Error('FULLY_FILLED');
+ }
+ try {
+ OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationTimeSeconds);
+ } catch (err) {
+ throw new Error('EXPIRED');
+ }
let fillTakerAssetAmount = signedOrder.takerAssetAmount.minus(filledTakerTokenAmount);
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
fillTakerAssetAmount = expectedFillTakerTokenAmount;
@@ -198,10 +208,9 @@ export class OrderValidationUtils {
throw new Error(OrderError.InvalidSignature);
}
const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
- OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
- signedOrder.takerAssetAmount,
- filledTakerTokenAmount,
- );
+ if (signedOrder.takerAssetAmount.eq(filledTakerTokenAmount)) {
+ throw new Error(RevertReason.OrderUnfillable);
+ }
if (signedOrder.takerAddress !== constants.NULL_ADDRESS && signedOrder.takerAddress !== takerAddress) {
throw new Error(RevertReason.InvalidTaker);
}
@@ -210,13 +219,30 @@ export class OrderValidationUtils {
const desiredFillTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerAssetAmount)
? remainingTakerTokenAmount
: fillTakerAssetAmount;
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- desiredFillTakerTokenAmount,
- takerAddress,
- zrxAssetData,
- );
+ try {
+ await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
+ exchangeTradeEmulator,
+ signedOrder,
+ desiredFillTakerTokenAmount,
+ takerAddress,
+ zrxAssetData,
+ );
+ } catch (err) {
+ const transferFailedErrorMessages = [
+ ExchangeContractErrs.InsufficientMakerBalance,
+ ExchangeContractErrs.InsufficientMakerFeeBalance,
+ ExchangeContractErrs.InsufficientTakerBalance,
+ ExchangeContractErrs.InsufficientTakerFeeBalance,
+ ExchangeContractErrs.InsufficientMakerAllowance,
+ ExchangeContractErrs.InsufficientMakerFeeAllowance,
+ ExchangeContractErrs.InsufficientTakerAllowance,
+ ExchangeContractErrs.InsufficientTakerFeeAllowance,
+ ];
+ if (_.includes(transferFailedErrorMessages, err.message)) {
+ throw new Error(RevertReason.TransferFailed);
+ }
+ throw err;
+ }
const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingErrorFloor(
desiredFillTakerTokenAmount,
@@ -228,33 +254,4 @@ export class OrderValidationUtils {
}
return filledTakerTokenAmount;
}
- /**
- * Validate a call to fillOrKillOrder and throw if it would fail
- * @param exchangeTradeEmulator ExchangeTradeEmulator to use
- * @param provider Web3 provider to use for JSON RPC requests
- * @param signedOrder SignedOrder of interest
- * @param fillTakerAssetAmount Amount we'd like to fill the order for
- * @param takerAddress The taker of the order
- * @param zrxAssetData ZRX asset data
- */
- public async validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator: ExchangeTransferSimulator,
- provider: Provider,
- signedOrder: SignedOrder,
- fillTakerAssetAmount: BigNumber,
- takerAddress: string,
- zrxAssetData: string,
- ): Promise<void> {
- const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- provider,
- signedOrder,
- fillTakerAssetAmount,
- takerAddress,
- zrxAssetData,
- );
- if (filledTakerTokenAmount !== fillTakerAssetAmount) {
- throw new Error(RevertReason.OrderUnfillable);
- }
- }
}
diff --git a/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts b/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts
index 1d84ffdaa..afd6f1108 100644
--- a/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts
+++ b/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts
@@ -1,8 +1,10 @@
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { AbstractOrderFilledCancelledFetcher } from '../abstract/abstract_order_filled_cancelled_fetcher';
import { AbstractOrderFilledCancelledLazyStore } from '../abstract/abstract_order_filled_cancelled_lazy_store';
+import { orderHashUtils } from '../order_hash';
/**
* Copy on read store for balances/proxyAllowances of tokens/accounts
@@ -58,9 +60,10 @@ export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancell
* @param orderHash OrderHash from order of interest
* @return Whether the order has been cancelled
*/
- public async getIsCancelledAsync(orderHash: string): Promise<boolean> {
+ public async getIsCancelledAsync(signedOrder: SignedOrder): Promise<boolean> {
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
if (_.isUndefined(this._isCancelled[orderHash])) {
- const isCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
+ const isCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder);
this.setIsCancelled(orderHash, isCancelled);
}
const cachedIsCancelled = this._isCancelled[orderHash]; // tslint:disable-line:boolean-naming
diff --git a/packages/order-utils/test/order_state_utils_test.ts b/packages/order-utils/test/order_state_utils_test.ts
index 39c4c362f..42acd54c6 100644
--- a/packages/order-utils/test/order_state_utils_test.ts
+++ b/packages/order-utils/test/order_state_utils_test.ts
@@ -1,3 +1,4 @@
+import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import 'mocha';
@@ -33,7 +34,7 @@ describe('OrderStateUtils', () => {
async getFilledTakerAmountAsync(_orderHash: string): Promise<BigNumber> {
return filledAmount;
},
- async isOrderCancelledAsync(_orderHash: string): Promise<boolean> {
+ async isOrderCancelledAsync(_signedOrder: SignedOrder): Promise<boolean> {
return cancelled;
},
getZRXAssetData(): string {
diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json
index d574f4a18..c662903a3 100644
--- a/packages/order-watcher/CHANGELOG.json
+++ b/packages/order-watcher/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.2.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "2.2.0",
"changes": [
{
diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md
index 299af5437..b271956c7 100644
--- a/packages/order-watcher/CHANGELOG.md
+++ b/packages/order-watcher/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.2.1 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.2.0 - _October 18, 2018_
* Added getStats function and returns a Stats object (#1118)
diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json
index 42e3f572c..174e0a3a6 100644
--- a/packages/order-watcher/package.json
+++ b/packages/order-watcher/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/order-watcher",
- "version": "2.2.0",
+ "version": "2.2.1",
"description": "An order watcher daemon that watches for order validity",
"keywords": [
"0x",
@@ -33,9 +33,9 @@
"node": ">=6.0.0"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/migrations": "^2.0.0",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/migrations": "^2.0.1",
+ "@0x/tslint-config": "^1.0.10",
"@types/bintrees": "^1.0.2",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
@@ -57,21 +57,21 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.0.1",
- "@0x/assert": "^1.0.14",
- "@0x/base-contract": "^3.0.2",
- "@0x/contract-addresses": "^1.0.1",
- "@0x/contract-artifacts": "^1.0.1",
- "@0x/contract-wrappers": "^3.0.0",
- "@0x/fill-scenarios": "^1.0.8",
- "@0x/json-schemas": "^2.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/abi-gen-wrappers": "^1.0.2",
+ "@0x/assert": "^1.0.15",
+ "@0x/base-contract": "^3.0.3",
+ "@0x/contract-addresses": "^1.1.0",
+ "@0x/contract-artifacts": "^1.1.0",
+ "@0x/contract-wrappers": "^3.0.1",
+ "@0x/fill-scenarios": "^1.0.9",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"bintrees": "^1.0.2",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-blockstream": "6.0.0",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json
index 97485be96..228dfab4f 100644
--- a/packages/react-docs/CHANGELOG.json
+++ b/packages/react-docs/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.15",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.14",
"changes": [
diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md
index 096bd8460..991b3a490 100644
--- a/packages/react-docs/CHANGELOG.md
+++ b/packages/react-docs/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.15 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.14 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json
index e234b0479..827a54fdb 100644
--- a/packages/react-docs/package.json
+++ b/packages/react-docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/react-docs",
- "version": "1.0.14",
+ "version": "1.0.15",
"engines": {
"node": ">=6.12"
},
@@ -24,8 +24,8 @@
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/tslint-config": "^1.0.10",
"@types/compare-versions": "^3.0.0",
"@types/styled-components": "^4.0.0",
"make-promises-safe": "^1.1.0",
@@ -34,9 +34,9 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/react-shared": "^1.0.17",
- "@0x/types": "^1.2.0",
- "@0x/utils": "^2.0.3",
+ "@0x/react-shared": "^1.0.18",
+ "@0x/types": "^1.2.1",
+ "@0x/utils": "^2.0.4",
"@types/lodash": "4.14.104",
"@types/material-ui": "^0.20.0",
"@types/node": "*",
diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json
index 8578b4603..4dd11398b 100644
--- a/packages/react-shared/CHANGELOG.json
+++ b/packages/react-shared/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.18",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "1.0.17",
"changes": [
{
diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md
index fc3f7e32c..54ca77b16 100644
--- a/packages/react-shared/CHANGELOG.md
+++ b/packages/react-shared/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.18 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.17 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json
index 45220e2d2..35a69f105 100644
--- a/packages/react-shared/package.json
+++ b/packages/react-shared/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/react-shared",
- "version": "1.0.17",
+ "version": "1.0.18",
"engines": {
"node": ">=6.12"
},
@@ -25,15 +25,15 @@
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/tslint-config": "^1.0.10",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
"tslint": "^5.9.1",
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/types": "^1.2.0",
+ "@0x/types": "^1.2.1",
"@material-ui/core": "^3.0.1",
"@types/is-mobile": "0.3.0",
"@types/lodash": "4.14.104",
diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json
index d945c305b..724e68a68 100644
--- a/packages/sol-compiler/CHANGELOG.json
+++ b/packages/sol-compiler/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.1.9",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.1.8",
"changes": [
diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md
index 1a86d097d..322313f9e 100644
--- a/packages/sol-compiler/CHANGELOG.md
+++ b/packages/sol-compiler/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.1.9 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.1.8 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json
index 17ccb50b8..766c789df 100644
--- a/packages/sol-compiler/package.json
+++ b/packages/sol-compiler/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-compiler",
- "version": "1.1.8",
+ "version": "1.1.9",
"engines": {
"node": ">=6.12"
},
@@ -42,8 +42,8 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md",
"devDependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/tslint-config": "^1.0.9",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/tslint-config": "^1.0.10",
"@types/mkdirp": "^0.5.2",
"@types/require-from-string": "^1.2.0",
"@types/semver": "^5.5.0",
@@ -65,16 +65,16 @@
"zeppelin-solidity": "1.8.0"
},
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/json-schemas": "^2.0.0",
- "@0x/sol-resolver": "^1.0.15",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/assert": "^1.0.15",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/sol-resolver": "^1.0.16",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/yargs": "^11.0.0",
"chalk": "^2.3.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.5",
"mkdirp": "^0.5.1",
diff --git a/packages/sol-cov/CHANGELOG.json b/packages/sol-cov/CHANGELOG.json
index cbee0233b..e331d608f 100644
--- a/packages/sol-cov/CHANGELOG.json
+++ b/packages/sol-cov/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.1.9",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "2.1.8",
"changes": [
{
diff --git a/packages/sol-cov/CHANGELOG.md b/packages/sol-cov/CHANGELOG.md
index 11ed486e2..e9d9d6952 100644
--- a/packages/sol-cov/CHANGELOG.md
+++ b/packages/sol-cov/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.1.9 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.1.8 - _October 18, 2018_
* Make @types/solidity-parser-antlr a 'dependency' so it's available to users of the library (#1105)
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index 09119321d..34e7a8559 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-cov",
- "version": "2.1.8",
+ "version": "2.1.9",
"engines": {
"node": ">=6.12"
},
@@ -42,14 +42,14 @@
},
"homepage": "https://github.com/0xProject/0x.js/packages/sol-cov/README.md",
"dependencies": {
- "@0x/dev-utils": "^1.0.13",
- "@0x/sol-compiler": "^1.1.8",
- "@0x/subproviders": "^2.1.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/dev-utils": "^1.0.14",
+ "@0x/sol-compiler": "^1.1.9",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@types/solidity-parser-antlr": "^0.2.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
"glob": "^7.1.2",
"istanbul": "^0.4.5",
@@ -61,7 +61,7 @@
"solidity-parser-antlr": "^0.2.12"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/istanbul": "^0.4.30",
"@types/loglevel": "^1.5.3",
"@types/mkdirp": "^0.5.1",
diff --git a/packages/sol-doc/CHANGELOG.json b/packages/sol-doc/CHANGELOG.json
index e117ff291..d54569a4d 100644
--- a/packages/sol-doc/CHANGELOG.json
+++ b/packages/sol-doc/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.4",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.3",
"changes": [
diff --git a/packages/sol-doc/CHANGELOG.md b/packages/sol-doc/CHANGELOG.md
index 9adc02b19..d44af5d7f 100644
--- a/packages/sol-doc/CHANGELOG.md
+++ b/packages/sol-doc/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.4 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.3 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/sol-doc/package.json b/packages/sol-doc/package.json
index b1e887fa5..0eb5d6fd5 100644
--- a/packages/sol-doc/package.json
+++ b/packages/sol-doc/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-doc",
- "version": "1.0.3",
+ "version": "1.0.4",
"description": "Solidity documentation generator",
"main": "lib/src/index.js",
"types": "lib/src/index.d.js",
@@ -25,16 +25,16 @@
"author": "F. Eugene Aumson",
"license": "Apache-2.0",
"dependencies": {
- "@0x/sol-compiler": "^1.1.8",
- "@0x/types": "^1.2.0",
- "@0x/utils": "^2.0.3",
- "ethereum-types": "^1.1.1",
+ "@0x/sol-compiler": "^1.1.9",
+ "@0x/types": "^1.2.1",
+ "@0x/utils": "^2.0.4",
+ "ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.10",
"yargs": "^12.0.2"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.2",
diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json
index a72ca6d63..a6ff84237 100644
--- a/packages/sol-resolver/CHANGELOG.json
+++ b/packages/sol-resolver/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.16",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.15",
"changes": [
diff --git a/packages/sol-resolver/CHANGELOG.md b/packages/sol-resolver/CHANGELOG.md
index 671d3ea84..f8c5a7692 100644
--- a/packages/sol-resolver/CHANGELOG.md
+++ b/packages/sol-resolver/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.16 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.15 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json
index 4d4d0be0e..7572072c4 100644
--- a/packages/sol-resolver/package.json
+++ b/packages/sol-resolver/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-resolver",
- "version": "1.0.15",
+ "version": "1.0.16",
"engines": {
"node": ">=6.12"
},
@@ -23,15 +23,15 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/resolver/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
"lodash": "^4.17.5"
},
"publishConfig": {
diff --git a/packages/sra-spec/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json
index a068df3fb..e053b3163 100644
--- a/packages/sra-spec/CHANGELOG.json
+++ b/packages/sra-spec/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.8",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "1.0.7",
"changes": [
{
diff --git a/packages/sra-spec/CHANGELOG.md b/packages/sra-spec/CHANGELOG.md
index ba4cddec2..02d22431f 100644
--- a/packages/sra-spec/CHANGELOG.md
+++ b/packages/sra-spec/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.8 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.7 - _October 18, 2018_
* Make @loopback/openapi-v3-types a 'dependency' so it's available to users of the library (#1105)
diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json
index 2d3e7decd..e3b6ad979 100644
--- a/packages/sra-spec/package.json
+++ b/packages/sra-spec/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sra-spec",
- "version": "1.0.7",
+ "version": "1.0.8",
"engines": {
"node": ">=6.12"
},
@@ -35,11 +35,11 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-spec/README.md",
"dependencies": {
- "@0x/json-schemas": "^2.0.0",
+ "@0x/json-schemas": "^2.0.1",
"@loopback/openapi-v3-types": "^0.8.2"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/mocha": "^2.2.42",
"@types/node": "^10.5.3",
"chai": "^4.0.1",
diff --git a/packages/sra-spec/src/json-schemas.ts b/packages/sra-spec/src/json-schemas.ts
index 9eb32de59..f9342ca9e 100644
--- a/packages/sra-spec/src/json-schemas.ts
+++ b/packages/sra-spec/src/json-schemas.ts
@@ -2,6 +2,7 @@ import { schemas as jsonSchemas } from '@0x/json-schemas';
// Only include schemas we actually need
const {
+ wholeNumberSchema,
numberSchema,
addressSchema,
hexSchema,
@@ -28,6 +29,7 @@ const {
} = jsonSchemas;
const usedSchemas = {
+ wholeNumberSchema,
numberSchema,
addressSchema,
hexSchema,
diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json
index b145bbbe5..816c776a5 100644
--- a/packages/subproviders/CHANGELOG.json
+++ b/packages/subproviders/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.1.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "2.1.0",
"changes": [
{
diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md
index f9e3e63a6..72ac9d1f7 100644
--- a/packages/subproviders/CHANGELOG.md
+++ b/packages/subproviders/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.1.1 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.1.0 - _October 18, 2018_
* Add `MetamaskSubprovider` to handle inconsistent JSON RPC behaviour (#1102)
diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json
index 32e2bae24..1a25b5e32 100644
--- a/packages/subproviders/package.json
+++ b/packages/subproviders/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/subproviders",
- "version": "2.1.0",
+ "version": "2.1.1",
"engines": {
"node": ">=6.12"
},
@@ -29,13 +29,13 @@
}
},
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/assert": "^1.0.15",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"@ledgerhq/hw-app-eth": "^4.3.0",
- "@ledgerhq/hw-transport-u2f": "^4.3.0",
+ "@ledgerhq/hw-transport-u2f": "4.24.0",
"@types/eth-lightwallet": "^3.0.0",
"@types/ganache-core": "^2.1.0",
"@types/hdkey": "^0.7.0",
@@ -43,7 +43,7 @@
"bip39": "^2.5.0",
"bn.js": "^4.11.8",
"eth-lightwallet": "^3.0.1",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-tx": "^1.3.5",
"ethereumjs-util": "^5.1.1",
"ganache-core": "^2.2.1",
@@ -54,7 +54,7 @@
"web3-provider-engine": "14.0.6"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/bip39": "^2.4.0",
"@types/bn.js": "^4.11.0",
"@types/ethereumjs-tx": "^1.0.0",
diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json
index 53f1b95df..c46f5465a 100644
--- a/packages/testnet-faucets/package.json
+++ b/packages/testnet-faucets/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@0x/testnet-faucets",
- "version": "1.0.52",
+ "version": "1.0.53",
"engines": {
"node": ">=6.12"
},
@@ -18,13 +18,13 @@
"author": "Fabio Berger",
"license": "Apache-2.0",
"dependencies": {
- "0x.js": "^2.0.0",
- "@0x/subproviders": "^2.1.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "0x.js": "^2.0.1",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"body-parser": "^1.17.1",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-tx": "^1.3.5",
"ethereumjs-util": "^5.1.1",
"express": "^4.15.2",
@@ -32,7 +32,7 @@
"rollbar": "^0.6.5"
},
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/body-parser": "^1.16.1",
"@types/express": "^4.0.35",
"@types/lodash": "4.14.104",
diff --git a/packages/tslint-config/CHANGELOG.json b/packages/tslint-config/CHANGELOG.json
index 99fbc7989..9f504216c 100644
--- a/packages/tslint-config/CHANGELOG.json
+++ b/packages/tslint-config/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.0.10",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "1.0.9",
"changes": [
diff --git a/packages/tslint-config/CHANGELOG.md b/packages/tslint-config/CHANGELOG.md
index f0b429d29..f5cacb5d1 100644
--- a/packages/tslint-config/CHANGELOG.md
+++ b/packages/tslint-config/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.10 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.0.9 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json
index a235532fb..2914f31e2 100644
--- a/packages/tslint-config/package.json
+++ b/packages/tslint-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/tslint-config",
- "version": "1.0.9",
+ "version": "1.0.10",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json
index 84a06faa8..6d9f83c57 100644
--- a/packages/types/CHANGELOG.json
+++ b/packages/types/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.2.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"version": "1.2.0",
"changes": [
{
diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md
index d1b8ea79c..556bf1799 100644
--- a/packages/types/CHANGELOG.md
+++ b/packages/types/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.2.1 - _November 9, 2018_
+
+ * Dependencies updated
+
## v1.2.0 - _October 18, 2018_
* Added `EIP712Parameter` `EIP712Types` `EIP712TypedData` for EIP712 signing (#1102)
diff --git a/packages/types/package.json b/packages/types/package.json
index 9b3ae6701..c32e9a6f7 100644
--- a/packages/types/package.json
+++ b/packages/types/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/types",
- "version": "1.2.0",
+ "version": "1.2.1",
"engines": {
"node": ">=6.12"
},
@@ -23,7 +23,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/types/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
"tslint": "5.11.0",
@@ -32,7 +32,7 @@
"dependencies": {
"@types/node": "*",
"bignumber.js": "~4.1.0",
- "ethereum-types": "^1.1.1"
+ "ethereum-types": "^1.1.2"
},
"publishConfig": {
"access": "public"
diff --git a/packages/typescript-typings/CHANGELOG.json b/packages/typescript-typings/CHANGELOG.json
index e21e788b5..5653b397d 100644
--- a/packages/typescript-typings/CHANGELOG.json
+++ b/packages/typescript-typings/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "3.0.4",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "3.0.3",
"changes": [
diff --git a/packages/typescript-typings/CHANGELOG.md b/packages/typescript-typings/CHANGELOG.md
index df58bfc57..62e6665be 100644
--- a/packages/typescript-typings/CHANGELOG.md
+++ b/packages/typescript-typings/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.4 - _November 9, 2018_
+
+ * Dependencies updated
+
## v3.0.3 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/typescript-typings/package.json b/packages/typescript-typings/package.json
index 6b9e67602..9dbbe1370 100644
--- a/packages/typescript-typings/package.json
+++ b/packages/typescript-typings/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/typescript-typings",
- "version": "3.0.3",
+ "version": "3.0.4",
"engines": {
"node": ">=6.12"
},
@@ -27,7 +27,7 @@
"@types/bn.js": "^4.11.0",
"@types/react": "*",
"bignumber.js": "~4.1.0",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"popper.js": "1.14.3"
},
"devDependencies": {
diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index 7594581d4..6c9da5f37 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.0.4",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1541740904
+ },
+ {
"timestamp": 1539871071,
"version": "2.0.3",
"changes": [
diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md
index 45b2cd0c2..4fdd13d9c 100644
--- a/packages/utils/CHANGELOG.md
+++ b/packages/utils/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.4 - _November 9, 2018_
+
+ * Dependencies updated
+
## v2.0.3 - _October 18, 2018_
* Dependencies updated
diff --git a/packages/utils/package.json b/packages/utils/package.json
index 4e0df9275..24c2496b0 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/utils",
- "version": "2.0.3",
+ "version": "2.0.4",
"engines": {
"node": ">=6.12"
},
@@ -28,7 +28,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/utils/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/detect-node": "2.0.0",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
@@ -41,13 +41,13 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
"@types/node": "*",
"abortcontroller-polyfill": "^1.1.9",
"bignumber.js": "~4.1.0",
"detect-node": "2.0.3",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
"ethers": "~4.0.4",
"isomorphic-fetch": "^2.2.1",
diff --git a/packages/utils/src/configured_bignumber.ts b/packages/utils/src/configured_bignumber.ts
index 2b22b6938..34b57d303 100644
--- a/packages/utils/src/configured_bignumber.ts
+++ b/packages/utils/src/configured_bignumber.ts
@@ -11,4 +11,27 @@ BigNumber.config({
DECIMAL_PLACES: 78,
});
+// Set a debug print function for NodeJS
+// Upstream issue: https://github.com/MikeMcl/bignumber.js/issues/188
+import isNode = require('detect-node');
+if (isNode) {
+ // Dynamically load a NodeJS specific module.
+ // Typescript requires all imports to be global, so we need to use
+ // `const` here and disable the tslint warning.
+ // tslint:disable-next-line: no-var-requires
+ const util = require('util');
+
+ // Set a custom util.inspect function
+ // HACK: We add a function to the BigNumber class by assigning to the
+ // prototype. The function name is a symbol provided by Node.
+ (BigNumber.prototype as any)[util.inspect.custom] = function(): string {
+ // HACK: When executed, `this` will refer to the BigNumber instance.
+ // This is also why we need a function expression instead of an
+ // arrow function, as the latter does not have a `this`.
+ // Return the readable string representation
+ // tslint:disable-next-line: no-invalid-this
+ return this.toString();
+ };
+}
+
export { BigNumber };
diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json
index 6b554110f..7b21da73a 100644
--- a/packages/web3-wrapper/CHANGELOG.json
+++ b/packages/web3-wrapper/CHANGELOG.json
@@ -7,7 +7,8 @@
"Fix bug in `getTransactionByHashAsync` which was causing the return value to have the wrong type (raw fields instead of unmarshalled fields).",
"pr": 1177
}
- ]
+ ],
+ "timestamp": 1541740904
},
{
"version": "3.1.0",
diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md
index 90d62953a..ebbef2c48 100644
--- a/packages/web3-wrapper/CHANGELOG.md
+++ b/packages/web3-wrapper/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.1.1 - _November 9, 2018_
+
+ * Fix bug in `getTransactionByHashAsync` which was causing the return value to have the wrong type (raw fields instead of unmarshalled fields). (#1177)
+
## v3.1.0 - _October 18, 2018_
* Add `signTypedData` to perform EIP712 `eth_signTypedData`. (#1102)
diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json
index e95245df8..2b87cc92a 100644
--- a/packages/web3-wrapper/package.json
+++ b/packages/web3-wrapper/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/web3-wrapper",
- "version": "3.1.0",
+ "version": "3.1.1",
"engines": {
"node": ">=6.12"
},
@@ -35,7 +35,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/web3-wrapper/README.md",
"devDependencies": {
- "@0x/tslint-config": "^1.0.9",
+ "@0x/tslint-config": "^1.0.10",
"@types/ganache-core": "^2.1.0",
"@types/lodash": "4.14.104",
"chai": "^4.0.1",
@@ -53,11 +53,11 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/assert": "^1.0.14",
- "@0x/json-schemas": "^2.0.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "ethereum-types": "^1.1.1",
+ "@0x/assert": "^1.0.15",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts
index 56877fef3..23204e616 100644
--- a/packages/web3-wrapper/src/web3_wrapper.ts
+++ b/packages/web3-wrapper/src/web3_wrapper.ts
@@ -533,9 +533,6 @@ export class Web3Wrapper {
method: 'eth_call',
params: [callDataHex, marshalledDefaultBlock],
});
- if (rawCallResult === '0x') {
- throw new Error('Contract call failed (returned null)');
- }
return rawCallResult;
}
/**
diff --git a/packages/website/package.json b/packages/website/package.json
index efb97d309..fd671d85d 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -1,40 +1,41 @@
{
"name": "@0x/website",
- "version": "0.0.55",
+ "version": "0.0.56",
"engines": {
"node": ">=6.12"
},
"private": true,
"description": "Website and 0x portal dapp",
"scripts": {
- "build": "node --max_old_space_size=8192 ../../node_modules/.bin/webpack --mode production",
+ "build": "yarn build:dev",
+ "build:prod": "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 --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",
- "deploy_live": "DEPLOY_ROLLBAR_SOURCEMAPS=true npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js"
+ "deploy_dogfood": "npm run build:prod; 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:prod; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
+ "deploy_live": "DEPLOY_ROLLBAR_SOURCEMAPS=true npm run build:prod; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js"
},
"author": "Fabio Berger",
"license": "Apache-2.0",
"dependencies": {
- "@0x/contract-wrappers": "^3.0.0",
- "@0x/json-schemas": "^2.0.0",
- "@0x/order-utils": "^2.0.0",
- "@0x/react-docs": "^1.0.14",
- "@0x/react-shared": "^1.0.17",
- "@0x/subproviders": "^2.1.0",
- "@0x/types": "^1.2.0",
- "@0x/typescript-typings": "^3.0.3",
- "@0x/utils": "^2.0.3",
- "@0x/web3-wrapper": "^3.1.0",
+ "@0x/contract-wrappers": "^3.0.1",
+ "@0x/json-schemas": "^2.0.1",
+ "@0x/order-utils": "^2.0.1",
+ "@0x/react-docs": "^1.0.15",
+ "@0x/react-shared": "^1.0.18",
+ "@0x/subproviders": "^2.1.1",
+ "@0x/types": "^1.2.1",
+ "@0x/typescript-typings": "^3.0.4",
+ "@0x/utils": "^2.0.4",
+ "@0x/web3-wrapper": "^3.1.1",
"accounting": "^0.4.1",
"basscss": "^8.0.3",
"blockies": "^0.0.2",
"bowser": "^1.9.3",
"deep-equal": "^1.0.1",
- "ethereum-types": "^1.1.1",
+ "ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
"find-versions": "^2.0.0",
"jsonschema": "^1.2.0",
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts
index b43c41739..25430c1c7 100644
--- a/packages/website/ts/blockchain.ts
+++ b/packages/website/ts/blockchain.ts
@@ -26,7 +26,7 @@ import { BlockParam, LogWithDecodedArgs, Provider, TransactionReceiptWithDecoded
import * as _ from 'lodash';
import * as moment from 'moment';
import * as React from 'react';
-import contract = require('truffle-contract');
+import contract from 'truffle-contract';
import { BlockchainWatcher } from 'ts/blockchain_watcher';
import { AssetSendCompleted } from 'ts/components/flash_messages/asset_send_completed';
import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted';
@@ -55,9 +55,9 @@ import { errorReporter } from 'ts/utils/error_reporter';
import { fakeTokenRegistry } from 'ts/utils/fake_token_registry';
import { tokenAddressOverrides } from 'ts/utils/token_address_overrides';
import { utils } from 'ts/utils/utils';
-import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
+import FilterSubprovider from 'web3-provider-engine/subproviders/filters';
-import * as MintableArtifacts from '../contracts/Mintable.json';
+import MintableArtifacts from '../contracts/Mintable.json';
const BLOCK_NUMBER_BACK_TRACK = 50;
const GWEI_IN_WEI = 1000000000;
diff --git a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
index a9f591150..e15a2dd94 100644
--- a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
+++ b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
@@ -7,7 +7,7 @@ import FlatButton from 'material-ui/FlatButton';
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
import TextField from 'material-ui/TextField';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
import { Blockchain } from 'ts/blockchain';
import { NetworkDropDown } from 'ts/components/dropdowns/network_drop_down';
import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx
index 2af4252bd..4a9f3b2fe 100644
--- a/packages/website/ts/components/eth_wrappers.tsx
+++ b/packages/website/ts/components/eth_wrappers.tsx
@@ -6,7 +6,7 @@ import Divider from 'material-ui/Divider';
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
import * as moment from 'moment';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
import { Blockchain } from 'ts/blockchain';
import { EthWethConversionButton } from 'ts/components/eth_weth_conversion_button';
import { Dispatcher } from 'ts/redux/dispatcher';
diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx
index 98aad6c62..e6ecd2ec8 100644
--- a/packages/website/ts/components/generate_order/asset_picker.tsx
+++ b/packages/website/ts/components/generate_order/asset_picker.tsx
@@ -3,7 +3,7 @@ import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import * as moment from 'moment';
import * as React from 'react';
-import firstBy = require('thenby');
+import firstBy from 'thenby';
import { Blockchain } from 'ts/blockchain';
import { NewTokenForm } from 'ts/components/generate_order/new_token_form';
diff --git a/packages/website/ts/components/inputs/allowance_state_toggle.tsx b/packages/website/ts/components/inputs/allowance_state_toggle.tsx
index fd7d3b174..5396295d2 100644
--- a/packages/website/ts/components/inputs/allowance_state_toggle.tsx
+++ b/packages/website/ts/components/inputs/allowance_state_toggle.tsx
@@ -2,7 +2,7 @@ import { colors } from '@0x/react-shared';
import { BigNumber, logUtils } from '@0x/utils';
import * as _ from 'lodash';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
import { Blockchain } from 'ts/blockchain';
import { AllowanceState, AllowanceStateView } from 'ts/components/ui/allowance_state_view';
import { Container } from 'ts/components/ui/container';
diff --git a/packages/website/ts/components/inputs/hash_input.tsx b/packages/website/ts/components/inputs/hash_input.tsx
index 73b6615d4..7688ffe21 100644
--- a/packages/website/ts/components/inputs/hash_input.tsx
+++ b/packages/website/ts/components/inputs/hash_input.tsx
@@ -3,7 +3,7 @@ import { Styles } from '@0x/react-shared';
import { Order } from '@0x/types';
import * as _ from 'lodash';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
import { Blockchain } from 'ts/blockchain';
import { FakeTextField } from 'ts/components/ui/fake_text_field';
diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx
index 9ba2bad84..92aecf046 100644
--- a/packages/website/ts/components/token_balances.tsx
+++ b/packages/website/ts/components/token_balances.tsx
@@ -16,8 +16,8 @@ import ContentAdd from 'material-ui/svg-icons/content/add';
import ContentRemove from 'material-ui/svg-icons/content/remove';
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
-import firstBy = require('thenby');
+import ReactTooltip from 'react-tooltip';
+import firstBy from 'thenby';
import { Blockchain } from 'ts/blockchain';
import { AssetPicker } from 'ts/components/generate_order/asset_picker';
import { SendButton } from 'ts/components/send_button';
diff --git a/packages/website/ts/components/ui/copy_icon.tsx b/packages/website/ts/components/ui/copy_icon.tsx
index 59e398cb6..403cd4607 100644
--- a/packages/website/ts/components/ui/copy_icon.tsx
+++ b/packages/website/ts/components/ui/copy_icon.tsx
@@ -2,7 +2,7 @@ import { colors } from '@0x/react-shared';
import * as React from 'react';
import * as CopyToClipboard from 'react-copy-to-clipboard';
import * as ReactDOM from 'react-dom';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
interface CopyIconProps {
data: string;
diff --git a/packages/website/ts/components/ui/ethereum_address.tsx b/packages/website/ts/components/ui/ethereum_address.tsx
index 71d98af56..12f8636eb 100644
--- a/packages/website/ts/components/ui/ethereum_address.tsx
+++ b/packages/website/ts/components/ui/ethereum_address.tsx
@@ -1,6 +1,6 @@
import { EtherscanLinkSuffixes } from '@0x/react-shared';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
import { EtherScanIcon } from 'ts/components/ui/etherscan_icon';
import { utils } from 'ts/utils/utils';
diff --git a/packages/website/ts/components/ui/etherscan_icon.tsx b/packages/website/ts/components/ui/etherscan_icon.tsx
index 57ab91ba2..a7fba8a33 100644
--- a/packages/website/ts/components/ui/etherscan_icon.tsx
+++ b/packages/website/ts/components/ui/etherscan_icon.tsx
@@ -1,7 +1,7 @@
import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
interface EtherScanIconProps {
addressOrTxHash: string;
diff --git a/packages/website/ts/components/ui/help_tooltip.tsx b/packages/website/ts/components/ui/help_tooltip.tsx
index d827eebb9..831d888f5 100644
--- a/packages/website/ts/components/ui/help_tooltip.tsx
+++ b/packages/website/ts/components/ui/help_tooltip.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
interface HelpTooltipProps {
style?: React.CSSProperties;
diff --git a/packages/website/ts/components/ui/identicon.tsx b/packages/website/ts/components/ui/identicon.tsx
index b5b374973..9eca04a5d 100644
--- a/packages/website/ts/components/ui/identicon.tsx
+++ b/packages/website/ts/components/ui/identicon.tsx
@@ -1,4 +1,4 @@
-import blockies = require('blockies');
+import blockies from 'blockies';
import * as _ from 'lodash';
import * as React from 'react';
diff --git a/packages/website/ts/components/ui/party.tsx b/packages/website/ts/components/ui/party.tsx
index 6c0572437..f9e0967d4 100644
--- a/packages/website/ts/components/ui/party.tsx
+++ b/packages/website/ts/components/ui/party.tsx
@@ -1,7 +1,7 @@
import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import ReactTooltip = require('react-tooltip');
+import ReactTooltip from 'react-tooltip';
import { EthereumAddress } from 'ts/components/ui/ethereum_address';
import { Identicon } from 'ts/components/ui/identicon';
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 326cd3cfa..d9da0b9d5 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
import * as React from 'react';
-import firstBy = require('thenby');
+import firstBy from 'thenby';
import { Blockchain } from 'ts/blockchain';
import { AccountConnection } from 'ts/components/ui/account_connection';
diff --git a/packages/website/ts/local_storage/trade_history_storage.tsx b/packages/website/ts/local_storage/trade_history_storage.tsx
index 91818b035..ef6a0a1aa 100644
--- a/packages/website/ts/local_storage/trade_history_storage.tsx
+++ b/packages/website/ts/local_storage/trade_history_storage.tsx
@@ -1,5 +1,5 @@
import { BigNumber } from '@0x/utils';
-import ethUtil = require('ethereumjs-util');
+import ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { localStorage } from 'ts/local_storage/local_storage';
import { Fill } from 'ts/types';
diff --git a/packages/website/ts/pages/documentation/developers_page.tsx b/packages/website/ts/pages/documentation/developers_page.tsx
index 361dbc86e..89389e488 100644
--- a/packages/website/ts/pages/documentation/developers_page.tsx
+++ b/packages/website/ts/pages/documentation/developers_page.tsx
@@ -1,7 +1,7 @@
import { colors, constants as sharedConstants, utils as sharedUtils } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import DocumentTitle = require('react-document-title');
+import DocumentTitle from 'react-document-title';
import { DocsLogo } from 'ts/components/documentation/docs_logo';
import { DocsTopBar } from 'ts/components/documentation/docs_top_bar';
import { Container } from 'ts/components/ui/container';
diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx
index 28bf2dba1..8392c90e4 100644
--- a/packages/website/ts/pages/documentation/doc_page.tsx
+++ b/packages/website/ts/pages/documentation/doc_page.tsx
@@ -6,11 +6,11 @@ import {
SupportedDocJson,
TypeDocUtils,
} from '@0x/react-docs';
-import findVersions = require('find-versions');
+import findVersions from 'find-versions';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
import * as React from 'react';
-import semverSort = require('semver-sort');
+import semverSort from 'semver-sort';
import { SidebarHeader } from 'ts/components/documentation/sidebar_header';
import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu';
import { Container } from 'ts/components/ui/container';
diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
index c56ed4ebe..e2af40c8d 100644
--- a/packages/website/ts/pages/landing/landing.tsx
+++ b/packages/website/ts/pages/landing/landing.tsx
@@ -1,7 +1,7 @@
import { colors, Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import DocumentTitle = require('react-document-title');
+import DocumentTitle from 'react-document-title';
import { Footer } from 'ts/components/footer';
import { SubscribeForm } from 'ts/components/forms/subscribe_form';
import { TopBar } from 'ts/components/top_bar/top_bar';
diff --git a/packages/website/ts/utils/doc_utils.ts b/packages/website/ts/utils/doc_utils.ts
index e0b883ace..6be164e6e 100644
--- a/packages/website/ts/utils/doc_utils.ts
+++ b/packages/website/ts/utils/doc_utils.ts
@@ -2,7 +2,7 @@ import { DocAgnosticFormat, GeneratedDocJson } from '@0x/react-docs';
import { fetchAsync, logUtils } from '@0x/utils';
import * as _ from 'lodash';
import { S3FileObject, VersionToFilePath } from 'ts/types';
-import convert = require('xml-js');
+import convert from 'xml-js';
export const docUtils = {
async getVersionToFilePathAsync(s3DocJsonRoot: string, folderName: string): Promise<VersionToFilePath> {
diff --git a/packages/website/ts/utils/error_reporter.ts b/packages/website/ts/utils/error_reporter.ts
index 6fc1216c3..8e24060ac 100644
--- a/packages/website/ts/utils/error_reporter.ts
+++ b/packages/website/ts/utils/error_reporter.ts
@@ -1,5 +1,5 @@
import { logUtils } from '@0x/utils';
-import Rollbar = require('rollbar');
+import Rollbar from 'rollbar';
import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';
diff --git a/packages/website/ts/utils/translate.ts b/packages/website/ts/utils/translate.ts
index 5595e6e0f..af5c766a9 100644
--- a/packages/website/ts/utils/translate.ts
+++ b/packages/website/ts/utils/translate.ts
@@ -1,11 +1,11 @@
import * as _ from 'lodash';
import { Deco, Key, Language } from 'ts/types';
-import * as chinese from '../../translations/chinese.json';
-import * as english from '../../translations/english.json';
-import * as korean from '../../translations/korean.json';
-import * as russian from '../../translations/russian.json';
-import * as spanish from '../../translations/spanish.json';
+import chinese from '../../translations/chinese.json';
+import english from '../../translations/english.json';
+import korean from '../../translations/korean.json';
+import russian from '../../translations/russian.json';
+import spanish from '../../translations/spanish.json';
const languageToTranslations = {
[Language.English]: english,
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
index 87aa48018..8cc0061de 100644
--- a/packages/website/ts/utils/utils.ts
+++ b/packages/website/ts/utils/utils.ts
@@ -5,7 +5,7 @@ import { ExchangeContractErrs } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as bowser from 'bowser';
-import deepEqual = require('deep-equal');
+import deepEqual from 'deep-equal';
import * as _ from 'lodash';
import * as moment from 'moment';
import * as numeral from 'numeral';
diff --git a/packages/website/tsconfig.json b/packages/website/tsconfig.json
index 6421cd459..7d5f31b7f 100644
--- a/packages/website/tsconfig.json
+++ b/packages/website/tsconfig.json
@@ -16,7 +16,9 @@
"composite": false,
"paths": {
"*": ["node_modules/@types/*", "*"]
- }
+ },
+ "module": "esnext",
+ "moduleResolution": "node"
},
"include": ["./ts/**/*"]
}
diff --git a/python-packages/order_utils/README.md b/python-packages/order_utils/README.md
index a266694db..4c5f7627c 100644
--- a/python-packages/order_utils/README.md
+++ b/python-packages/order_utils/README.md
@@ -18,7 +18,7 @@ Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting
### Install Code and Dependencies
-Ensure that you have Python >=3.6 installed, then:
+Ensure that you have installed Python >=3.6 and Docker. Then:
```bash
pip install -e .[dev]
@@ -26,7 +26,7 @@ pip install -e .[dev]
### Test
-`./setup.py test`
+Tests depend on a running ganache instance with the 0x contracts deployed in it. For convenience, a docker container is provided that has ganache-cli and a snapshot containing the necessary contracts. A shortcut is provided to run that docker container: `./setup.py ganache`. With that running, the tests can be run with `./setup.py test`.
### Clean
diff --git a/python-packages/order_utils/setup.py b/python-packages/order_utils/setup.py
index 22a5f4c41..1b07b612c 100755
--- a/python-packages/order_utils/setup.py
+++ b/python-packages/order_utils/setup.py
@@ -5,11 +5,12 @@
import subprocess # nosec
from shutil import rmtree
from os import environ, path
+from pathlib import Path
from sys import argv
from distutils.command.clean import clean
import distutils.command.build_py
-from setuptools import setup
+from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand
@@ -59,8 +60,15 @@ class LintCommand(distutils.command.build_py.build_py):
import eth_abi
eth_abi_dir = path.dirname(path.realpath(eth_abi.__file__))
- with open(path.join(eth_abi_dir, "py.typed"), "a"):
- pass
+ Path(path.join(eth_abi_dir, "py.typed")).touch()
+
+ # HACK(gene): until eth_utils fixes
+ # https://github.com/ethereum/eth-utils/issues/140 , we need to simply
+ # create an empty file `py.typed` in the eth_abi package directory.
+ import eth_utils
+
+ eth_utils_dir = path.dirname(path.realpath(eth_utils.__file__))
+ Path(path.join(eth_utils_dir, "py.typed")).touch()
for lint_command in lint_commands:
print(
@@ -79,7 +87,7 @@ class CleanCommandExtension(clean):
rmtree(".mypy_cache", ignore_errors=True)
rmtree(".tox", ignore_errors=True)
rmtree(".pytest_cache", ignore_errors=True)
- rmtree("src/order_utils.egg-info", ignore_errors=True)
+ rmtree("src/0x_order_utils.egg-info", ignore_errors=True)
# pylint: disable=too-many-ancestors
@@ -111,6 +119,26 @@ class PublishCommand(distutils.command.build_py.build_py):
subprocess.check_call("twine upload dist/*".split()) # nosec
+# pylint: disable=too-many-ancestors
+class GanacheCommand(distutils.command.build_py.build_py):
+ """Custom command to publish to pypi.org."""
+
+ description = "Run ganache daemon to support tests."
+
+ def run(self):
+ """Run ganache."""
+ cmd_line = (
+ "docker run -d -p 8545:8545 0xorg/ganache-cli --gasLimit"
+ + " 10000000 --db /snapshot --noVMErrorsOnRPCResponse -p 8545"
+ + " --networkId 50 -m"
+ ).split()
+ cmd_line.append(
+ "concert load couple harbor equip island argue ramp clarify fence"
+ + " smart topic"
+ )
+ subprocess.call(cmd_line) # nosec
+
+
with open("README.md", "r") as file_handle:
README_MD = file_handle.read()
@@ -130,9 +158,9 @@ setup(
"test": TestCommandExtension,
"test_publish": TestPublishCommand,
"publish": PublishCommand,
+ "ganache": GanacheCommand,
},
- include_package_data=True,
- install_requires=["eth-abi", "mypy_extensions", "web3"],
+ install_requires=["eth-abi", "eth_utils", "mypy_extensions", "web3"],
extras_require={
"dev": [
"bandit",
@@ -151,14 +179,17 @@ setup(
]
},
python_requires=">=3.6, <4",
- package_data={"zero_ex.order_utils": ["py.typed"]},
+ package_data={
+ "zero_ex.order_utils": ["py.typed"],
+ "zero_ex.contract_artifacts": ["artifacts/*"],
+ },
package_dir={"": "src"},
license="Apache 2.0",
keywords=(
"ethereum cryptocurrency 0x decentralized blockchain dex exchange"
),
namespace_packages=["zero_ex"],
- packages=["zero_ex.order_utils", "zero_ex.dev_utils"],
+ packages=find_packages("src"),
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
diff --git a/python-packages/order_utils/src/conf.py b/python-packages/order_utils/src/conf.py
index 606cd3b2a..6b6776d01 100644
--- a/python-packages/order_utils/src/conf.py
+++ b/python-packages/order_utils/src/conf.py
@@ -3,6 +3,7 @@
# Reference: http://www.sphinx-doc.org/en/master/config
from typing import List
+import pkg_resources
# pylint: disable=invalid-name
@@ -12,7 +13,7 @@ project = "0x-order-utils"
# pylint: disable=redefined-builtin
copyright = "2018, ZeroEx, Intl."
author = "F. Eugene Aumson"
-version = "0.1.0" # The short X.Y version
+version = pkg_resources.get_distribution("0x-order-utils").version
release = "" # The full version, including alpha/beta/rc tags
extensions = [
diff --git a/python-packages/order_utils/src/index.rst b/python-packages/order_utils/src/index.rst
index 22d5b0ef9..b99addabd 100644
--- a/python-packages/order_utils/src/index.rst
+++ b/python-packages/order_utils/src/index.rst
@@ -19,6 +19,9 @@ Python zero_ex.order_utils
See source for class properties. Sphinx does not easily generate class property docs; pull requests welcome.
+.. automodule:: zero_ex.order_utils.signature_utils
+ :members:
+
Indices and tables
==================
diff --git a/python-packages/order_utils/src/zero_ex/contract_artifacts/__init__.py b/python-packages/order_utils/src/zero_ex/contract_artifacts/__init__.py
new file mode 100644
index 000000000..ed45d2c8e
--- /dev/null
+++ b/python-packages/order_utils/src/zero_ex/contract_artifacts/__init__.py
@@ -0,0 +1 @@
+"""Solc-generated artifacts for 0x smart contracts."""
diff --git a/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts b/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
new file mode 120000
index 000000000..82d28ba87
--- /dev/null
+++ b/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
@@ -0,0 +1 @@
+../../../../../packages/contract-artifacts/artifacts \ No newline at end of file
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 a100da567..08c1b0ea5 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
@@ -46,3 +46,13 @@ def assert_is_int(value: Any, name: str) -> None:
f"expected variable '{name}', with value {str(value)}, to have"
+ f" type 'int', not '{type(value).__name__}'"
)
+
+
+def assert_is_hex_string(value: Any, name: str) -> None:
+ """Assert that :param value: is a string of hex chars.
+
+ If :param value: isn't a str, raise a TypeError. If it is a string but
+ contains non-hex characters ("0x" prefix permitted), raise a ValueError.
+ """
+ assert_is_string(value, name)
+ int(value, 16) # raises a ValueError if value isn't a base-16 str
diff --git a/python-packages/order_utils/src/zero_ex/order_utils/__init__.py b/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
index f014af0f6..80445cb6e 100644
--- a/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
+++ b/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
@@ -1 +1,11 @@
-"""Order utilities for 0x applications."""
+"""Order utilities for 0x applications.
+
+Some methods require the caller to pass in a `Web3.HTTPProvider` object. For
+local testing one may construct such a provider pointing at an instance of
+`ganache-cli <https://www.npmjs.com/package/ganache-cli>`_ which has the 0x
+contracts deployed on it. For convenience, a docker container is provided for
+just this purpose. To start it: ``docker run -d -p 8545:8545 0xorg/ganache-cli
+--gasLimit 10000000 --db /snapshot --noVMErrorsOnRPCResponse -p 8545
+--networkId 50 -m "concert load couple harbor equip island argue ramp clarify
+fence smart topic"``.
+"""
diff --git a/python-packages/order_utils/src/zero_ex/py.typed b/python-packages/order_utils/src/zero_ex/order_utils/py.typed
index e69de29bb..e69de29bb 100644
--- a/python-packages/order_utils/src/zero_ex/py.typed
+++ b/python-packages/order_utils/src/zero_ex/order_utils/py.typed
diff --git a/python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py b/python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py
new file mode 100644
index 000000000..12525ba88
--- /dev/null
+++ b/python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py
@@ -0,0 +1,88 @@
+"""Signature utilities."""
+
+from typing import Dict, Tuple
+import json
+from pkg_resources import resource_string
+
+from eth_utils import is_address, to_checksum_address
+from web3 import Web3
+import web3.exceptions
+from web3.utils import datatypes
+
+from zero_ex.dev_utils.type_assertions import assert_is_hex_string
+
+
+# prefer `black` formatting. pylint: disable=C0330
+EXCHANGE_ABI = json.loads(
+ resource_string("zero_ex.contract_artifacts", "artifacts/Exchange.json")
+)["compilerOutput"]["abi"]
+
+network_to_exchange_addr: Dict[str, str] = {
+ "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b",
+ "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf",
+ "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2",
+ "50": "0x48bacb9266a570d521063ef5dd96e61686dbe788",
+}
+
+
+# prefer `black` formatting. pylint: disable=C0330
+def is_valid_signature(
+ provider: Web3.HTTPProvider, data: str, signature: str, signer_address: str
+) -> Tuple[bool, str]:
+ # docstring considered all one line by pylint: disable=line-too-long
+ """Check the validity of the supplied signature.
+
+ Check if the supplied ``signature`` corresponds to signing ``data`` with
+ the private key corresponding to ``signer_address``.
+
+ :param provider: A Web3 provider able to access the 0x Exchange contract.
+ :param data: The hex encoded data signed by the supplied signature.
+ :param signature: The hex encoded signature.
+ :param signer_address: The hex encoded address that signed the data to
+ produce the supplied signature.
+ :rtype: Boolean indicating whether the given signature is valid.
+
+ >>> is_valid_signature(
+ ... Web3.HTTPProvider("http://127.0.0.1:8545"),
+ ... '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0',
+ ... '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403',
+ ... '0x5409ed021d9299bf6814279a6a1411a7e866a631',
+ ... )
+ (True, '')
+ """ # noqa: E501 (line too long)
+ # TODO: make this provider check more flexible. pylint: disable=fixme
+ # https://app.asana.com/0/684263176955174/901300863045491/f
+ if not isinstance(provider, Web3.HTTPProvider):
+ raise TypeError("provider is not a Web3.HTTPProvider")
+ assert_is_hex_string(data, "data")
+ assert_is_hex_string(signature, "signature")
+ assert_is_hex_string(signer_address, "signer_address")
+ if not is_address(signer_address):
+ raise ValueError("signer_address is not a valid address")
+
+ web3_instance = Web3(provider)
+ # false positive from pylint: disable=no-member
+ network_id = web3_instance.net.version
+ contract_address = network_to_exchange_addr[network_id]
+ # false positive from pylint: disable=no-member
+ contract: datatypes.Contract = web3_instance.eth.contract(
+ address=to_checksum_address(contract_address), abi=EXCHANGE_ABI
+ )
+ try:
+ return (
+ contract.call().isValidSignature(
+ data, to_checksum_address(signer_address), signature
+ ),
+ "",
+ )
+ except web3.exceptions.BadFunctionCallOutput as exception:
+ known_revert_reasons = [
+ "LENGTH_GREATER_THAN_0_REQUIRED",
+ "SIGNATURE_UNSUPPORTED",
+ "LENGTH_0_REQUIRED",
+ "LENGTH_65_REQUIRED",
+ ]
+ for known_revert_reason in known_revert_reasons:
+ if known_revert_reason in str(exception):
+ return (False, known_revert_reason)
+ return (False, f"Unknown: {exception}")
diff --git a/python-packages/order_utils/stubs/setuptools/__init__.pyi b/python-packages/order_utils/stubs/setuptools/__init__.pyi
index baa349d70..8ea8d32b7 100644
--- a/python-packages/order_utils/stubs/setuptools/__init__.pyi
+++ b/python-packages/order_utils/stubs/setuptools/__init__.pyi
@@ -1,6 +1,8 @@
from distutils.dist import Distribution
-from typing import Any
+from typing import Any, List
def setup(**attrs: Any) -> Distribution: ...
class Command: ...
+
+def find_packages(where: str) -> List[str]: ...
diff --git a/python-packages/order_utils/stubs/web3/__init__.pyi b/python-packages/order_utils/stubs/web3/__init__.pyi
index c6f357009..fcecc7434 100644
--- a/python-packages/order_utils/stubs/web3/__init__.pyi
+++ b/python-packages/order_utils/stubs/web3/__init__.pyi
@@ -1,10 +1,26 @@
-from typing import Optional, Union
+from typing import Dict, Optional, Union
+
+from web3.utils import datatypes
+
class Web3:
+ class HTTPProvider: ...
+
+ def __init__(self, provider: HTTPProvider) -> None: ...
+
@staticmethod
def sha3(
primitive: Optional[Union[bytes, int, None]] = None,
text: Optional[str] = None,
hexstr: Optional[str] = None
) -> bytes: ...
+
+ class net:
+ version: str
+ ...
+
+ class eth:
+ @staticmethod
+ def contract(address: str, abi: Dict) -> datatypes.Contract: ...
+ ...
...
diff --git a/python-packages/order_utils/stubs/web3/exceptions.pyi b/python-packages/order_utils/stubs/web3/exceptions.pyi
new file mode 100644
index 000000000..83abf973d
--- /dev/null
+++ b/python-packages/order_utils/stubs/web3/exceptions.pyi
@@ -0,0 +1,2 @@
+class BadFunctionCallOutput(Exception):
+ ...
diff --git a/python-packages/order_utils/stubs/web3/utils/__init__.pyi b/python-packages/order_utils/stubs/web3/utils/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/order_utils/stubs/web3/utils/__init__.pyi
diff --git a/python-packages/order_utils/stubs/web3/utils/datatypes.pyi b/python-packages/order_utils/stubs/web3/utils/datatypes.pyi
new file mode 100644
index 000000000..70baff372
--- /dev/null
+++ b/python-packages/order_utils/stubs/web3/utils/datatypes.pyi
@@ -0,0 +1,3 @@
+class Contract:
+ def call(self): ...
+ ...
diff --git a/python-packages/order_utils/test/test_doctest.py b/python-packages/order_utils/test/test_doctest.py
index ba5da5418..2b0350ac0 100644
--- a/python-packages/order_utils/test/test_doctest.py
+++ b/python-packages/order_utils/test/test_doctest.py
@@ -1,24 +1,18 @@
-"""Exercise doctests for order_utils module."""
+"""Exercise doctests for all of our modules."""
from doctest import testmod
+import pkgutil
-from zero_ex.dev_utils import abi_utils, type_assertions
-from zero_ex.order_utils import asset_data_utils
+import zero_ex
-def test_doctest_asset_data_utils():
- """Invoke doctest on the asset_data_utils module."""
- (failure_count, _) = testmod(asset_data_utils)
- assert failure_count == 0
-
-
-def test_doctest_abi_utils():
- """Invoke doctest on the abi_utils module."""
- (failure_count, _) = testmod(abi_utils)
- assert failure_count == 0
-
-
-def test_doctest_type_assertions():
- """Invoke doctest on the type_assertions module."""
- (failure_count, _) = testmod(type_assertions)
- assert failure_count == 0
+def test_all_doctests():
+ """Gather zero_ex.* modules and doctest them."""
+ # prefer `black` formatting. pylint: disable=bad-continuation
+ for (importer, modname, _) in pkgutil.walk_packages(
+ path=zero_ex.__path__, prefix="zero_ex."
+ ):
+ module = importer.find_module(modname).load_module(modname)
+ print(module)
+ (failure_count, _) = testmod(module)
+ assert failure_count == 0
diff --git a/python-packages/order_utils/test/test_signature_utils.py b/python-packages/order_utils/test/test_signature_utils.py
new file mode 100644
index 000000000..b688e03a1
--- /dev/null
+++ b/python-packages/order_utils/test/test_signature_utils.py
@@ -0,0 +1,128 @@
+"""Tests of zero_ex.order_utils.signature_utils."""
+
+import pytest
+from web3 import Web3
+
+from zero_ex.order_utils.signature_utils import is_valid_signature
+
+
+def test_is_valid_signature__provider_wrong_type():
+ """Test that giving a non-HTTPProvider raises a TypeError."""
+ with pytest.raises(TypeError):
+ is_valid_signature(
+ 123,
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
+ + "0",
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
+ + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
+ + "225403",
+ "0x5409ed021d9299bf6814279a6a1411a7e866a631",
+ )
+
+
+def test_is_valid_signature__data_not_string():
+ """Test that giving non-string `data` raises a TypeError."""
+ with pytest.raises(TypeError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ 123,
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
+ + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
+ + "225403",
+ "0x5409ed021d9299bf6814279a6a1411a7e866a631",
+ )
+
+
+def test_is_valid_signature__data_not_hex_string():
+ """Test that giving non-hex-string `data` raises a ValueError."""
+ with pytest.raises(ValueError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "jjj",
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
+ + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
+ + "225403",
+ "0x5409ed021d9299bf6814279a6a1411a7e866a631",
+ )
+
+
+def test_is_valid_signature__signature_not_string():
+ """Test that passng a non-string signature raises a TypeError."""
+ with pytest.raises(TypeError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
+ + "0",
+ 123,
+ "0x5409ed021d9299bf6814279a6a1411a7e866a631",
+ )
+
+
+def test_is_valid_signature__signature_not_hex_string():
+ """Test that passing a non-hex-string signature raises a ValueError."""
+ with pytest.raises(ValueError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
+ + "0",
+ "jjj",
+ "0x5409ed021d9299bf6814279a6a1411a7e866a631",
+ )
+
+
+def test_is_valid_signature__signer_address_not_string():
+ """Test that giving a non-address `signer_address` raises a ValueError."""
+ with pytest.raises(TypeError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
+ + "0",
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
+ + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
+ + "225403",
+ 123,
+ )
+
+
+def test_is_valid_signature__signer_address_not_hex_string():
+ """Test that giving a non-hex-str `signer_address` raises a ValueError."""
+ with pytest.raises(ValueError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
+ + "0",
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
+ + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
+ + "225403",
+ "jjj",
+ )
+
+
+def test_is_valid_signature__signer_address_not_valid_address():
+ """Test that giving a non-address for `signer_address` raises an error."""
+ with pytest.raises(ValueError):
+ is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b"
+ + "0",
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351b"
+ + "c3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace"
+ + "225403",
+ "0xff",
+ )
+
+
+def test_is_valid_signature__unsupported_sig_types():
+ """Test that passing in a sig w/invalid type raises error.
+
+ To induce this error, the last byte of the signature is tweaked from 03 to
+ ff."""
+ (is_valid, reason) = is_valid_signature(
+ Web3.HTTPProvider("http://127.0.0.1:8545"),
+ "0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0",
+ "0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc334"
+ + "0349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254ff",
+ "0x5409ed021d9299bf6814279a6a1411a7e866a631",
+ )
+ assert is_valid is False
+ assert reason == "SIGNATURE_UNSUPPORTED"
diff --git a/yarn.lock b/yarn.lock
index 18d143ed5..b23ec92d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -541,13 +541,19 @@
"@ledgerhq/hw-transport" "^4.7.3"
node-hid "^0.7.2"
-"@ledgerhq/hw-transport-u2f@^4.3.0":
- version "4.7.3"
- resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-u2f/-/hw-transport-u2f-4.7.3.tgz#32be84bd2829f0ad0745604355f73a169dceb5e5"
+"@ledgerhq/hw-transport-u2f@4.24.0":
+ version "4.24.0"
+ resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-u2f/-/hw-transport-u2f-4.24.0.tgz#d67cfc4abf6d9a900ed45f2e2df7fe06dfdff5c7"
dependencies:
- "@ledgerhq/hw-transport" "^4.7.3"
+ "@ledgerhq/hw-transport" "^4.24.0"
u2f-api "0.2.7"
+"@ledgerhq/hw-transport@^4.24.0":
+ version "4.24.0"
+ resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-4.24.0.tgz#8def925d8c2e1f73d15128d9e27ead729870be58"
+ dependencies:
+ events "^3.0.0"
+
"@ledgerhq/hw-transport@^4.7.3":
version "4.7.3"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-4.7.3.tgz#e89cd90d30aaf008adf9fdfa4af317a48fe798ca"
@@ -1148,15 +1154,15 @@
dependencies:
samsam "1.3.0"
-"@static/discharge@^1.2.2":
+"@static/discharge@https://github.com/0xProject/discharge.git":
version "1.2.2"
- resolved "https://registry.npmjs.org/@static/discharge/-/discharge-1.2.2.tgz#dc941e0c02c421b338b83ac2e59e140d7214c971"
+ resolved "https://github.com/0xProject/discharge.git#3aed990822cabbb79b71b52700fdef08cd9eb400"
dependencies:
- aws-sdk "^2.304.0"
+ aws-sdk "^2.347.0"
execa "^1.0.0"
glob "^7.1.3"
inquirer "^6.2.0"
- listr "^0.14.1"
+ listr "^0.14.2"
lodash.differenceby "^4.8.0"
lodash.intersectionby "^4.7.0"
lodash.intersectionwith "^4.4.0"
@@ -1900,6 +1906,10 @@ aes-js@^0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d"
+aes-js@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072"
+
agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
@@ -2324,9 +2334,9 @@ aws-sdk@^2.127.0:
uuid "3.1.0"
xml2js "0.4.19"
-aws-sdk@^2.304.0:
- version "2.338.0"
- resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.338.0.tgz#f1b1347f78defa27b92b030b5787fad0f89ac83b"
+aws-sdk@^2.347.0:
+ version "2.348.0"
+ resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.348.0.tgz#69c5b6dd77a5eac85b54bf7cc1640c19d762d3ee"
dependencies:
buffer "4.9.1"
events "1.1.1"
@@ -3337,7 +3347,7 @@ bs-logger@0.x:
dependencies:
fast-json-stable-stringify "^2.0.0"
-bs58@=4.0.1:
+bs58@=4.0.1, bs58@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
dependencies:
@@ -3360,6 +3370,14 @@ bs58check@^1.0.8:
bs58 "^3.1.0"
create-hash "^1.1.0"
+bs58check@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
+ dependencies:
+ bs58 "^4.0.0"
+ create-hash "^1.1.0"
+ safe-buffer "^5.1.2"
+
bser@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
@@ -4389,9 +4407,9 @@ copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
-copy-to-clipboard@^3:
+copy-to-clipboard@^3, copy-to-clipboard@^3.0.8:
version "3.0.8"
- resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9"
+ resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9"
dependencies:
toggle-selection "^1.0.3"
@@ -5947,6 +5965,19 @@ ethereumjs-wallet@0.6.0:
utf8 "^2.1.1"
uuid "^2.0.1"
+ethereumjs-wallet@~0.6.0:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda"
+ dependencies:
+ aes-js "^3.1.1"
+ bs58check "^2.1.2"
+ ethereumjs-util "^5.2.0"
+ hdkey "^1.0.0"
+ safe-buffer "^5.1.2"
+ scrypt.js "^0.2.0"
+ utf8 "^3.0.0"
+ uuid "^3.3.2"
+
ethers@~4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.4.tgz#d3f85e8b27f4b59537e06526439b0fb15b44dc65"
@@ -6024,6 +6055,10 @@ events@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/events/-/events-2.0.0.tgz#cbbb56bf3ab1ac18d71c43bb32c86255062769f2"
+events@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
+
eventsource@0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232"
@@ -7476,6 +7511,14 @@ hdkey@^0.7.0, hdkey@^0.7.1:
coinstring "^2.0.0"
secp256k1 "^3.0.1"
+hdkey@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29"
+ dependencies:
+ coinstring "^2.0.0"
+ safe-buffer "^5.1.1"
+ secp256k1 "^3.0.1"
+
he@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
@@ -9449,7 +9492,7 @@ listr@^0.12.0:
stream-to-observable "^0.1.0"
strip-ansi "^3.0.1"
-listr@^0.14.1:
+listr@^0.14.2:
version "0.14.2"
resolved "https://registry.npmjs.org/listr/-/listr-0.14.2.tgz#cbe44b021100a15376addfc2d79349ee430bfe14"
dependencies:
@@ -15562,6 +15605,10 @@ utf8@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96"
+utf8@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
+
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"