aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--README.md3
-rw-r--r--packages/0x.js/package.json2
-rw-r--r--packages/abi-gen/package.json2
-rw-r--r--packages/assert/CHANGELOG.json10
-rw-r--r--packages/assert/src/index.ts4
-rw-r--r--packages/base-contract/package.json2
-rw-r--r--packages/base-contract/src/index.ts2
-rw-r--r--packages/contract-wrappers/CHANGELOG.json8
-rw-r--r--packages/contract-wrappers/package.json6
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts13
-rw-r--r--packages/contract-wrappers/src/utils/decorators.ts8
-rw-r--r--packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts3
-rw-r--r--packages/contract-wrappers/src/utils/filter_utils.ts4
-rw-r--r--packages/contract-wrappers/test/ether_token_wrapper_test.ts4
-rw-r--r--packages/contract-wrappers/test/exchange_wrapper_test.ts4
-rw-r--r--packages/contract-wrappers/test/subscription_test.ts2
-rw-r--r--packages/contract-wrappers/test/token_wrapper_test.ts4
-rw-r--r--packages/contracts/.solhint.json17
-rw-r--r--packages/contracts/package.json9
-rw-r--r--packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol2
-rw-r--r--packages/contracts/src/2.0.0/multisig/MultiSigWalletWithTimeLock.sol2
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/MixinAuthorizable.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetData.sol5
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetProxy.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAuthorizable.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/libs/LibAssetProxyErrors.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/mixins/MAuthorizable.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/Exchange.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchange.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchangeCore.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IMatchOrders.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ISignatureValidator.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ITransactions.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IValidator.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWallet.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWrapperFunctions.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol2
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibEIP712.sol2
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibExchangeErrors.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibFillResults.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol4
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/mixins/MAssetProxyDispatcher.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/mixins/MMatchOrders.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol1
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/mixins/MTransactions.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/DummyERC20Token/DummyERC20Token.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/DummyERC721Receiver/DummyERC721Receiver.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/DummyERC721Token/DummyERC721Token.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/ExchangeWrapper/ExchangeWrapper.sol2
-rw-r--r--packages/contracts/src/2.0.0/test/Mintable/Mintable.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/TestAssetProxyOwner/TestAssetProxyOwner.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/TestLibBytes/TestLibBytes.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol1
-rw-r--r--packages/contracts/src/2.0.0/test/TestValidator/TestValidator.sol2
-rw-r--r--packages/contracts/src/2.0.0/test/TestWallet/TestWallet.sol2
-rw-r--r--packages/contracts/src/2.0.0/test/Whitelist/Whitelist.sol5
-rw-r--r--packages/contracts/src/2.0.0/tokens/ERC20Token/ERC20Token.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/ERC20Token/IERC20Token.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/ERC721Token/ERC721Token.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Receiver.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Token.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/WETH9/WETH9.sol1
-rw-r--r--packages/contracts/src/2.0.0/tokens/ZRXToken/ZRXToken.sol2
-rw-r--r--packages/contracts/src/2.0.0/utils/LibBytes/LibBytes.sol1
-rw-r--r--packages/contracts/src/2.0.0/utils/Ownable/Ownable.sol1
-rw-r--r--packages/contracts/src/2.0.0/utils/SafeMath/SafeMath.sol1
-rw-r--r--packages/contracts/test/asset_proxy/authorizable.ts18
-rw-r--r--packages/contracts/test/asset_proxy/proxies.ts16
-rw-r--r--packages/contracts/test/exchange/core.ts36
-rw-r--r--packages/contracts/test/exchange/dispatcher.ts8
-rw-r--r--packages/contracts/test/exchange/fill_order.ts9
-rw-r--r--packages/contracts/test/exchange/match_orders.ts12
-rw-r--r--packages/contracts/test/exchange/signature_validator.ts10
-rw-r--r--packages/contracts/test/exchange/transactions.ts16
-rw-r--r--packages/contracts/test/exchange/wrapper.ts12
-rw-r--r--packages/contracts/test/libraries/lib_bytes.ts46
-rw-r--r--packages/contracts/test/multisig/asset_proxy_owner.ts21
-rw-r--r--packages/contracts/test/multisig/multi_sig_with_time_lock.ts8
-rw-r--r--packages/contracts/test/token_registry.ts32
-rw-r--r--packages/contracts/test/tokens/ether_token.ts4
-rw-r--r--packages/contracts/test/tokens/unlimited_allowance_token.ts8
-rw-r--r--packages/contracts/test/utils/assertions.ts169
-rw-r--r--packages/contracts/test/utils/asset_wrapper.ts11
-rw-r--r--packages/contracts/test/utils/constants.ts1
-rw-r--r--packages/contracts/test/utils/core_combinatorial_utils.ts136
-rw-r--r--packages/dev-utils/package.json5
-rw-r--r--packages/dev-utils/src/blockchain_lifecycle.ts26
-rw-r--r--packages/dev-utils/src/web3_factory.ts5
-rw-r--r--packages/ethereum-types/CHANGELOG.json4
-rw-r--r--packages/ethereum-types/package.json2
-rw-r--r--packages/ethereum-types/src/index.ts4
-rw-r--r--packages/fill-scenarios/CHANGELOG.json2
-rw-r--r--packages/fill-scenarios/package.json2
-rw-r--r--packages/json-schemas/CHANGELOG.json13
-rw-r--r--packages/json-schemas/schemas/call_data_schema.ts27
-rw-r--r--packages/json-schemas/src/schemas.ts2
-rw-r--r--packages/metacoin/package.json2
-rw-r--r--packages/migrations/package.json4
-rw-r--r--packages/monorepo-scripts/CHANGELOG.json9
-rw-r--r--packages/monorepo-scripts/src/prepublish_checks.ts12
-rw-r--r--packages/monorepo-scripts/src/utils/utils.ts27
-rw-r--r--packages/order-utils/CHANGELOG.json6
-rw-r--r--packages/order-utils/package.json2
-rw-r--r--packages/order-utils/src/order_validation_utils.ts6
-rw-r--r--packages/order-watcher/package.json4
-rw-r--r--packages/order-watcher/src/order_watcher/order_watcher.ts14
-rw-r--r--packages/sol-compiler/package.json3
-rw-r--r--packages/sol-cov/package.json2
-rw-r--r--packages/subproviders/CHANGELOG.json8
-rw-r--r--packages/subproviders/package.json14
-rw-r--r--packages/subproviders/src/globals.d.ts5
-rw-r--r--packages/subproviders/src/index.ts3
-rw-r--r--packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts68
-rw-r--r--packages/subproviders/src/subproviders/signer.ts (renamed from packages/subproviders/src/subproviders/injected_web3.ts)45
-rw-r--r--packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts167
-rw-r--r--packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts14
-rw-r--r--packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts5
-rw-r--r--packages/testnet-faucets/package.json6
-rw-r--r--packages/testnet-faucets/src/ts/dispense_asset_tasks.ts15
-rw-r--r--packages/testnet-faucets/src/ts/handler.ts17
-rw-r--r--packages/types/CHANGELOG.json11
-rw-r--r--packages/types/package.json2
-rw-r--r--packages/types/src/index.ts6
-rw-r--r--packages/typescript-typings/CHANGELOG.json4
-rw-r--r--packages/typescript-typings/package.json2
-rw-r--r--packages/typescript-typings/types/eth-lightwallet/index.d.ts50
-rw-r--r--packages/utils/CHANGELOG.json13
-rw-r--r--packages/utils/package.json7
-rw-r--r--packages/web3-wrapper/CHANGELOG.json10
-rw-r--r--packages/web3-wrapper/package.json8
-rw-r--r--packages/web3-wrapper/src/index.ts2
-rw-r--r--packages/web3-wrapper/src/marshaller.ts149
-rw-r--r--packages/web3-wrapper/src/types.ts56
-rw-r--r--packages/web3-wrapper/src/utils.ts58
-rw-r--r--packages/web3-wrapper/src/web3_wrapper.ts264
-rw-r--r--packages/web3-wrapper/test/web3_wrapper_test.ts95
-rw-r--r--packages/website/package.json5
-rw-r--r--packages/website/public/images/lock_icon.svg3
-rw-r--r--packages/website/public/images/setup_account_icon.svg3
-rw-r--r--packages/website/public/images/team/alexbrowne.pngbin0 -> 146699 bytes
-rw-r--r--packages/website/public/images/toshi_logo.jpgbin0 -> 4611 bytes
-rw-r--r--packages/website/public/index.html13
-rw-r--r--packages/website/translations/english.json3
-rw-r--r--packages/website/ts/blockchain.ts31
-rw-r--r--packages/website/ts/blockchain_watcher.ts7
-rw-r--r--packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx2
-rw-r--r--packages/website/ts/components/dialogs/send_dialog.tsx1
-rw-r--r--packages/website/ts/components/inputs/balance_bounded_input.tsx35
-rw-r--r--packages/website/ts/components/inputs/eth_amount_input.tsx4
-rw-r--r--packages/website/ts/components/inputs/token_amount_input.tsx2
-rw-r--r--packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx47
-rw-r--r--packages/website/ts/components/onboarding/onboarding_card.tsx2
-rw-r--r--packages/website/ts/components/onboarding/onboarding_flow.tsx54
-rw-r--r--packages/website/ts/components/onboarding/portal_onboarding_flow.tsx63
-rw-r--r--packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx2
-rw-r--r--packages/website/ts/components/portal/portal.tsx78
-rw-r--r--packages/website/ts/components/relayer_index/relayer_grid_tile.tsx9
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx118
-rw-r--r--packages/website/ts/components/top_bar/provider_picker.tsx79
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx51
-rw-r--r--packages/website/ts/components/top_bar/top_bar_menu_item.tsx26
-rw-r--r--packages/website/ts/components/ui/button.tsx21
-rw-r--r--packages/website/ts/components/ui/container.tsx1
-rw-r--r--packages/website/ts/components/ui/drop_down.tsx52
-rw-r--r--packages/website/ts/components/ui/image.tsx4
-rw-r--r--packages/website/ts/components/ui/simple_menu.tsx88
-rw-r--r--packages/website/ts/components/ui/text.tsx5
-rw-r--r--packages/website/ts/components/wallet/body_overlay.tsx36
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx115
-rw-r--r--packages/website/ts/components/wallet/wrap_ether_item.tsx5
-rw-r--r--packages/website/ts/containers/subproviders_documentation.ts3
-rw-r--r--packages/website/ts/pages/about/about.tsx29
-rw-r--r--packages/website/ts/pages/landing/landing.tsx12
-rw-r--r--packages/website/ts/redux/store.ts4
-rw-r--r--packages/website/ts/style/media.ts14
-rw-r--r--packages/website/ts/types.ts33
-rw-r--r--packages/website/ts/utils/analytics.ts11
-rw-r--r--packages/website/ts/utils/constants.ts7
-rw-r--r--packages/website/ts/utils/translate.ts13
-rw-r--r--packages/website/ts/utils/utils.ts86
-rw-r--r--yarn.lock460
195 files changed, 2646 insertions, 1040 deletions
diff --git a/.gitignore b/.gitignore
index 350e12995..feab4f31f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,6 +67,9 @@ generated_docs/
TODO.md
+# VSCode file
+.vscode
+
packages/website/public/bundle*
packages/react-docs/example/public/bundle*
diff --git a/README.md b/README.md
index 6615ae4dc..1d6aa08a9 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,11 @@
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
+If you're developing on 0x now or are interested in using 0x infrastructure in the future, please join our [developer mailing list][dev-mailing-list-url] for updates.
+
[website-url]: https://0xproject.com/
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
+[dev-mailing-list-url]: http://eepurl.com/dx4cPf
[![CircleCI](https://circleci.com/gh/0xProject/0x-monorepo.svg?style=svg&circle-token=61bf7cd8c9b4e11b132089dfcffdd1be277d1e0c)](https://circleci.com/gh/0xProject/0x-monorepo)
[![Coverage Status](https://coveralls.io/repos/github/0xProject/0x-monorepo/badge.svg?branch=development)](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index 12fbf0347..1b41a7cf2 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -110,7 +110,7 @@
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"ethers": "3.0.22",
"lodash": "^4.17.4"
},
diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json
index 9d3c6d00d..dadf1dbfe 100644
--- a/packages/abi-gen/package.json
+++ b/packages/abi-gen/package.json
@@ -29,7 +29,7 @@
"dependencies": {
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"chalk": "^2.3.0",
"glob": "^7.1.2",
"handlebars": "^4.0.11",
diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json
index 883d55f5b..b44cac4a1 100644
--- a/packages/assert/CHANGELOG.json
+++ b/packages/assert/CHANGELOG.json
@@ -1,5 +1,15 @@
[
{
+ "version": "0.2.13",
+ "changes": [
+ {
+ "note":
+ "Fix bug in string enum assertion. We erroneously were checking against the enum keys, not values",
+ "pr": 821
+ }
+ ]
+ },
+ {
"timestamp": 1529397769,
"version": "0.2.12",
"changes": [
diff --git a/packages/assert/src/index.ts b/packages/assert/src/index.ts
index 95c7b658b..8e18416c5 100644
--- a/packages/assert/src/index.ts
+++ b/packages/assert/src/index.ts
@@ -41,8 +41,8 @@ export const assert = {
value: string,
stringEnum: any /* There is no base type for every string enum */,
): void {
- const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]);
- const enumValues = _.keys(stringEnum);
+ const enumValues = _.values(stringEnum);
+ const doesBelongToStringEnum = _.includes(enumValues, value);
const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`);
const enumValuesAsString = enumValuesAsStrings.join(', ');
assert.assert(
diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json
index ecbde213b..3b9383033 100644
--- a/packages/base-contract/package.json
+++ b/packages/base-contract/package.json
@@ -43,7 +43,7 @@
"typescript": "2.7.1"
},
"dependencies": {
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
diff --git a/packages/base-contract/src/index.ts b/packages/base-contract/src/index.ts
index cb9042415..6b970ec27 100644
--- a/packages/base-contract/src/index.ts
+++ b/packages/base-contract/src/index.ts
@@ -80,7 +80,7 @@ export class BaseContract {
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
} as any;
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
- txDataWithDefaults.gas = await estimateGasAsync(txData);
+ txDataWithDefaults.gas = await estimateGasAsync(txDataWithDefaults as any);
}
return txDataWithDefaults;
}
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index 33d9bc4c0..e34b50c1a 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,5 +1,13 @@
[
{
+ "version": "0.0.6",
+ "changes": [
+ {
+ "note": "Update blockstream to v5.0 and propogate up caught errors to active subscriptions"
+ }
+ ]
+ },
+ {
"timestamp": 1529397769,
"version": "0.0.5",
"changes": [
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index fe98e08bf..373e023bd 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -74,7 +74,7 @@
"source-map-support": "^0.5.0",
"tslint": "5.8.0",
"typescript": "2.7.1",
- "web3-provider-engine": "^14.0.4"
+ "web3-provider-engine": "14.0.6"
},
"dependencies": {
"@0xproject/assert": "^0.2.12",
@@ -86,8 +86,8 @@
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
- "ethereum-types": "^0.0.1",
- "ethereumjs-blockstream": "^2.0.6",
+ "ethereum-types": "^0.0.2",
+ "ethereumjs-blockstream": "5.0.0",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
"js-sha3": "^0.7.0",
diff --git a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
index 04f69bc3d..9cc661080 100644
--- a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
@@ -9,7 +9,7 @@ import {
} from '@0xproject/types';
import { intervalUtils } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
+import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
import * as _ from 'lodash';
import {
@@ -39,7 +39,7 @@ export abstract class ContractWrapper {
public abstract abi: ContractAbi;
protected _web3Wrapper: Web3Wrapper;
protected _networkId: number;
- private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
+ private _blockAndLogStreamerIfExists: BlockAndLogStreamer<Block, Log> | undefined;
private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
private _filters: { [filterToken: string]: FilterObject };
private _filterCallbacks: {
@@ -163,6 +163,7 @@ export abstract class ContractWrapper {
this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
+ this._onBlockAndLogStreamerError.bind(this),
);
const catchAllLogFilter = {};
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
@@ -180,6 +181,14 @@ export abstract class ContractWrapper {
this._onLogStateChanged.bind(this, isRemoved),
);
}
+ private _onBlockAndLogStreamerError(err: Error): void {
+ // Propogate all Blockstream subscriber errors to all
+ // top-level subscriptions
+ const filterCallbacks = _.values(this._filterCallbacks);
+ _.each(filterCallbacks, filterCallback => {
+ filterCallback(err);
+ });
+ }
private _onReconcileBlockError(err: Error): void {
const filterTokens = _.keys(this._filterCallbacks);
_.each(filterTokens, filterToken => {
diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts
index 494575e7b..ccb4c6e11 100644
--- a/packages/contract-wrappers/src/utils/decorators.ts
+++ b/packages/contract-wrappers/src/utils/decorators.ts
@@ -30,8 +30,8 @@ const schemaErrorTransformer = (error: Error) => {
*/
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const asyncErrorHandlingDecorator = (
- target: object,
- key: string | symbol,
+ _target: object,
+ _key: string | symbol,
descriptor: TypedPropertyDescriptor<AsyncMethod>,
) => {
const originalMethod = descriptor.value as AsyncMethod;
@@ -57,8 +57,8 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const syncErrorHandlingDecorator = (
- target: object,
- key: string | symbol,
+ _target: object,
+ _key: string | symbol,
descriptor: TypedPropertyDescriptor<SyncMethod>,
) => {
const originalMethod = descriptor.value as SyncMethod;
diff --git a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts
index 527b8575d..279f2a796 100644
--- a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts
+++ b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts
@@ -1,8 +1,7 @@
-import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types';
+import { ExchangeContractErrs } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
-import { TokenWrapper } from '../contract_wrappers/token_wrapper';
import { TradeSide, TransferType } from '../types';
import { constants } from '../utils/constants';
diff --git a/packages/contract-wrappers/src/utils/filter_utils.ts b/packages/contract-wrappers/src/utils/filter_utils.ts
index 5256d010f..f96dc573f 100644
--- a/packages/contract-wrappers/src/utils/filter_utils.ts
+++ b/packages/contract-wrappers/src/utils/filter_utils.ts
@@ -30,7 +30,7 @@ export const filterUtils = {
blockRange?: BlockRange,
): FilterObject {
const eventAbi = _.find(abi, { name: eventName }) as EventAbi;
- const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
+ const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi);
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
const topics = [topicForEventSignature, ...topicsForIndexedArgs];
@@ -46,7 +46,7 @@ export const filterUtils = {
}
return filter;
},
- getEventSignatureFromAbiByName(eventAbi: EventAbi, eventName: ContractEvents): string {
+ getEventSignatureFromAbiByName(eventAbi: EventAbi): string {
const types = _.map(eventAbi.inputs, 'type');
const signature = `${eventAbi.name}(${types.join(',')})`;
return signature;
diff --git a/packages/contract-wrappers/test/ether_token_wrapper_test.ts b/packages/contract-wrappers/test/ether_token_wrapper_test.ts
index b13ac72bb..f401ef90a 100644
--- a/packages/contract-wrappers/test/ether_token_wrapper_test.ts
+++ b/packages/contract-wrappers/test/ether_token_wrapper_test.ts
@@ -277,7 +277,7 @@ describe('EtherTokenWrapper', () => {
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
+ (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
},
);
@@ -307,7 +307,7 @@ describe('EtherTokenWrapper', () => {
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
+ (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
},
);
diff --git a/packages/contract-wrappers/test/exchange_wrapper_test.ts b/packages/contract-wrappers/test/exchange_wrapper_test.ts
index cf69d4813..c945b4c70 100644
--- a/packages/contract-wrappers/test/exchange_wrapper_test.ts
+++ b/packages/contract-wrappers/test/exchange_wrapper_test.ts
@@ -999,7 +999,7 @@ describe('ExchangeWrapper', () => {
it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
+ (_logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
},
);
@@ -1024,7 +1024,7 @@ describe('ExchangeWrapper', () => {
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
+ (_logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
},
);
diff --git a/packages/contract-wrappers/test/subscription_test.ts b/packages/contract-wrappers/test/subscription_test.ts
index 4d638bf9b..b9417ca3d 100644
--- a/packages/contract-wrappers/test/subscription_test.ts
+++ b/packages/contract-wrappers/test/subscription_test.ts
@@ -80,7 +80,7 @@ describe('SubscriptionTest', () => {
});
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
(async () => {
- const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
+ const callback = (_err: Error | null, _logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
stubs = [
Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockAsync').throws(
diff --git a/packages/contract-wrappers/test/token_wrapper_test.ts b/packages/contract-wrappers/test/token_wrapper_test.ts
index c9722c7b4..86b93b3f9 100644
--- a/packages/contract-wrappers/test/token_wrapper_test.ts
+++ b/packages/contract-wrappers/test/token_wrapper_test.ts
@@ -484,7 +484,7 @@ describe('TokenWrapper', () => {
it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
+ (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
},
);
@@ -508,7 +508,7 @@ describe('TokenWrapper', () => {
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
+ (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
},
);
diff --git a/packages/contracts/.solhint.json b/packages/contracts/.solhint.json
new file mode 100644
index 000000000..7e3b4dca2
--- /dev/null
+++ b/packages/contracts/.solhint.json
@@ -0,0 +1,17 @@
+{
+ "extends": "default",
+ "rules": {
+ "bracket-align": "warn",
+ "code-complexity": "warn",
+ "const-name-snakecase": "warn",
+ "expression-indent": "warn",
+ "function-max-lines": "warn",
+ "statement-indent": "warn",
+ "indent": ["warn", 4],
+ "quotes": ["error", "double"],
+ "max-line-length": ["warn", 120],
+ "separate-by-one-line-in-contract": "warn",
+ "space-after-comma": "error",
+ "func-order": "warn"
+ }
+}
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index 3b496ad58..a8bbdbe16 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -29,7 +29,8 @@
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
- "test:circleci": "yarn test"
+ "test:circleci": "yarn test",
+ "lint-contracts": "solhint src/2.0.0/**/*.sol"
},
"config": {
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyOwner|TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TestValidator|TestWallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
@@ -65,6 +66,7 @@
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solc": "^0.4.24",
+ "solhint": "^1.2.1",
"tslint": "5.8.0",
"typescript": "2.7.1",
"yargs": "^10.0.3"
@@ -77,12 +79,11 @@
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"bn.js": "^4.11.8",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
- "lodash": "^4.17.4",
- "web3": "^0.20.0"
+ "lodash": "^4.17.4"
}
} \ No newline at end of file
diff --git a/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol b/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol
index 79fd92029..1ceecd907 100644
--- a/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol
+++ b/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol
@@ -1,5 +1,7 @@
pragma solidity ^0.4.10;
+// solhint-disable
+
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
/// @author Stefan George - <stefan.george@consensys.net>
contract MultiSigWallet {
diff --git a/packages/contracts/src/2.0.0/multisig/MultiSigWalletWithTimeLock.sol b/packages/contracts/src/2.0.0/multisig/MultiSigWalletWithTimeLock.sol
index 9766c2158..d714b661d 100644
--- a/packages/contracts/src/2.0.0/multisig/MultiSigWalletWithTimeLock.sol
+++ b/packages/contracts/src/2.0.0/multisig/MultiSigWalletWithTimeLock.sol
@@ -20,6 +20,8 @@ pragma solidity ^0.4.10;
import "./MultiSigWallet.sol";
+// solhint-disable
+
/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
/// @author Amir Bandeali - <amir@0xProject.com>
contract MultiSigWalletWithTimeLock is MultiSigWallet {
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/MixinAuthorizable.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/MixinAuthorizable.sol
index 3b9584a44..5bc5f3a47 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxy/MixinAuthorizable.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/MixinAuthorizable.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../../utils/Ownable/Ownable.sol";
import "./mixins/MAuthorizable.sol";
+
contract MixinAuthorizable is
Ownable,
MAuthorizable
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetData.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetData.sol
index 7ebd6acf0..b4ff2d900 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetData.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetData.sol
@@ -18,15 +18,18 @@
pragma solidity ^0.4.23;
+
// @dev Interface of the asset proxy's assetData.
// The asset proxies take an ABI encoded `bytes assetData` as argument.
// This argument is ABI encoded as one of the methods of this interface.
interface IAssetData {
-
+
+ // solhint-disable-next-line func-name-mixedcase
function ERC20Token(address tokenContract)
external
pure;
+ // solhint-disable-next-line func-name-mixedcase
function ERC721Token(
address tokenContract,
uint256 tokenId,
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetProxy.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetProxy.sol
index eacd5a412..0ef1ed2e0 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetProxy.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAssetProxy.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "./IAuthorizable.sol";
+
contract IAssetProxy is
IAuthorizable
{
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAuthorizable.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAuthorizable.sol
index cedd1744c..286db74aa 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAuthorizable.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/interfaces/IAuthorizable.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../../../utils/Ownable/IOwnable.sol";
+
contract IAuthorizable is
IOwnable
{
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/libs/LibAssetProxyErrors.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
index 338cb12e2..4b460ea9a 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
/// @dev This contract documents the revert reasons used in the AssetProxy contracts.
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
contract LibAssetProxyErrors {
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/mixins/MAuthorizable.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/mixins/MAuthorizable.sol
index 6f35bd7ec..66c259a23 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxy/mixins/MAuthorizable.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/mixins/MAuthorizable.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../interfaces/IAuthorizable.sol";
+
contract MAuthorizable is
IAuthorizable
{
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol b/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol
index eb58b3374..232155a6b 100644
--- a/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol
+++ b/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol
@@ -21,6 +21,7 @@ pragma solidity ^0.4.10;
import "../../multisig/MultiSigWalletWithTimeLock.sol";
import "../../utils/LibBytes/LibBytes.sol";
+
contract AssetProxyOwner is
MultiSigWalletWithTimeLock
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/Exchange.sol b/packages/contracts/src/2.0.0/protocol/Exchange/Exchange.sol
index d36e9633e..effff82e0 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/Exchange.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/Exchange.sol
@@ -27,6 +27,7 @@ import "./MixinAssetProxyDispatcher.sol";
import "./MixinTransactions.sol";
import "./MixinMatchOrders.sol";
+
contract Exchange is
MixinExchangeCore,
MixinMatchOrders,
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol
index 9e9d88ce7..dcfe9e1de 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol
@@ -23,6 +23,7 @@ import "../../utils/LibBytes/LibBytes.sol";
import "./mixins/MAssetProxyDispatcher.sol";
import "../AssetProxy/interfaces/IAssetProxy.sol";
+
contract MixinAssetProxyDispatcher is
Ownable,
MAssetProxyDispatcher
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol
index d377dc943..9e63dc1c0 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol
@@ -28,6 +28,7 @@ import "./mixins/MSignatureValidator.sol";
import "./mixins/MTransactions.sol";
import "./mixins/MAssetProxyDispatcher.sol";
+
contract MixinExchangeCore is
LibConstants,
LibMath,
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol
index 1a43eec79..bfe838837 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol
@@ -23,6 +23,7 @@ import "./mixins/MMatchOrders.sol";
import "./mixins/MTransactions.sol";
import "./mixins/MAssetProxyDispatcher.sol";
+
contract MixinMatchOrders is
LibConstants,
LibMath,
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol
index 29172057a..78f13286f 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol
@@ -24,6 +24,7 @@ import "./mixins/MTransactions.sol";
import "./interfaces/IWallet.sol";
import "./interfaces/IValidator.sol";
+
contract MixinSignatureValidator is
MSignatureValidator,
MTransactions
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol
index 31f7f2847..3b18ac733 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol
@@ -22,6 +22,7 @@ import "./mixins/MSignatureValidator.sol";
import "./mixins/MTransactions.sol";
import "./libs/LibEIP712.sol";
+
contract MixinTransactions is
LibEIP712,
MSignatureValidator,
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol
index 00668ca43..678d0252a 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol
@@ -24,6 +24,7 @@ import "./libs/LibOrder.sol";
import "./libs/LibFillResults.sol";
import "./mixins/MExchangeCore.sol";
+
contract MixinWrapperFunctions is
LibMath,
LibFillResults,
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
index 66f3b5796..b73881c07 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
contract IAssetProxyDispatcher {
/// @dev Registers an asset proxy to its asset proxy id.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchange.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchange.sol
index 9f21c18d7..05e5dedf4 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchange.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchange.sol
@@ -26,6 +26,7 @@ import "./ITransactions.sol";
import "./IAssetProxyDispatcher.sol";
import "./IWrapperFunctions.sol";
+
contract IExchange is
IExchangeCore,
IMatchOrders,
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchangeCore.sol
index 98222f33f..2b573eb1a 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchangeCore.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IExchangeCore.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
+
contract IExchangeCore {
/// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IMatchOrders.sol
index df009d063..d44116474 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IMatchOrders.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IMatchOrders.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
+
contract IMatchOrders {
/// @dev Match two complementary orders that have a profitable spread.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ISignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ISignatureValidator.sol
index 511463309..c5a4a57e1 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ISignatureValidator.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ISignatureValidator.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
contract ISignatureValidator {
/// @dev Approves a hash on-chain using any valid signature type.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ITransactions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ITransactions.sol
index a7cab8f55..aaaee389f 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ITransactions.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/ITransactions.sol
@@ -17,6 +17,7 @@
*/
pragma solidity ^0.4.24;
+
contract ITransactions {
/// @dev Executes an exchange method call in the context of signer.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IValidator.sol
index 0b1796a66..2c0a5dbe2 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IValidator.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IValidator.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.23;
+
contract IValidator {
/// @dev Verifies that a signature is valid.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWallet.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWallet.sol
index c86a2c057..c2db4a5b1 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWallet.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWallet.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
contract IWallet {
/// @dev Verifies that a signature is valid.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWrapperFunctions.sol
index 84bb683bc..04257b883 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWrapperFunctions.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/interfaces/IWrapperFunctions.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
+
contract IWrapperFunctions {
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
/// @param order LibOrder.Order struct containing order specifications.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol
index 488ca956c..76200ec44 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol
@@ -18,11 +18,13 @@
pragma solidity ^0.4.24;
+
contract LibConstants {
// Asset data for ZRX token. Used for fee transfers.
// @TODO: Hardcode constant when we deploy. Currently
// not constant to make testing easier.
+ // solhint-disable-next-line var-name-mixedcase
bytes public ZRX_ASSET_DATA;
// @TODO: Remove when we deploy.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibEIP712.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibEIP712.sol
index b983347a4..2bd7b60d4 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibEIP712.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibEIP712.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
contract LibEIP712 {
// EIP191 header for EIP712 prefix
string constant EIP191_HEADER = "\x19\x01";
@@ -38,6 +39,7 @@ contract LibEIP712 {
));
// Hash of the EIP712 Domain Separator data
+ // solhint-disable-next-line var-name-mixedcase
bytes32 public EIP712_DOMAIN_HASH;
constructor ()
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibExchangeErrors.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibExchangeErrors.sol
index 01aa78a1d..99f683e1a 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibExchangeErrors.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibExchangeErrors.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
/// @dev This contract documents the revert reasons used in the Exchange contract.
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
contract LibExchangeErrors {
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibFillResults.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibFillResults.sol
index 63f1b8c87..35fa9ac0f 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibFillResults.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibFillResults.sol
@@ -20,6 +20,7 @@ pragma solidity ^0.4.24;
import "../../../utils/SafeMath/SafeMath.sol";
+
contract LibFillResults is
SafeMath
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol
index bfe2fd33f..9da784854 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol
@@ -20,6 +20,7 @@ pragma solidity ^0.4.24;
import "../../../utils/SafeMath/SafeMath.sol";
+
contract LibMath is
SafeMath
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol
index 954f94f76..dda581d9f 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol
@@ -20,6 +20,7 @@ pragma solidity ^0.4.24;
import "./LibEIP712.sol";
+
contract LibOrder is
LibEIP712
{
@@ -115,17 +116,20 @@ contract LibOrder is
// ));
assembly {
// Backup
+ // solhint-disable-next-line space-after-comma
let temp1 := mload(sub(order, 32))
let temp2 := mload(add(order, 320))
let temp3 := mload(add(order, 352))
// Hash in place
+ // solhint-disable-next-line space-after-comma
mstore(sub(order, 32), schemaHash)
mstore(add(order, 320), makerAssetDataHash)
mstore(add(order, 352), takerAssetDataHash)
result := keccak256(sub(order, 32), 416)
// Restore
+ // solhint-disable-next-line space-after-comma
mstore(sub(order, 32), temp1)
mstore(add(order, 320), temp2)
mstore(add(order, 352), temp3)
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MAssetProxyDispatcher.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
index 5bf59c6ce..367b37e80 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../interfaces/IAssetProxyDispatcher.sol";
+
contract MAssetProxyDispatcher is
IAssetProxyDispatcher
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol
index 6e406e1c4..e28d9d25b 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol
@@ -23,6 +23,7 @@ import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
import "../interfaces/IExchangeCore.sol";
+
contract MExchangeCore is
IExchangeCore
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MMatchOrders.sol
index abe7c3596..289514b24 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MMatchOrders.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MMatchOrders.sol
@@ -22,6 +22,7 @@ import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
import "../interfaces/IMatchOrders.sol";
+
contract MMatchOrders is
IMatchOrders
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol
index 6cc1d7a10..83650b4aa 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol
@@ -20,6 +20,7 @@ pragma solidity ^0.4.24;
import "../interfaces/ISignatureValidator.sol";
+
contract MSignatureValidator is
ISignatureValidator
{
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MTransactions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MTransactions.sol
index e2f89de01..a9fa6d4e2 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MTransactions.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MTransactions.sol
@@ -19,6 +19,7 @@ pragma solidity ^0.4.24;
import "../interfaces/ITransactions.sol";
+
contract MTransactions is
ITransactions
{
diff --git a/packages/contracts/src/2.0.0/test/DummyERC20Token/DummyERC20Token.sol b/packages/contracts/src/2.0.0/test/DummyERC20Token/DummyERC20Token.sol
index b2fe2df06..7a2702449 100644
--- a/packages/contracts/src/2.0.0/test/DummyERC20Token/DummyERC20Token.sol
+++ b/packages/contracts/src/2.0.0/test/DummyERC20Token/DummyERC20Token.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../Mintable/Mintable.sol";
import "../../utils/Ownable/Ownable.sol";
+
contract DummyERC20Token is Mintable, Ownable {
string public name;
string public symbol;
diff --git a/packages/contracts/src/2.0.0/test/DummyERC721Receiver/DummyERC721Receiver.sol b/packages/contracts/src/2.0.0/test/DummyERC721Receiver/DummyERC721Receiver.sol
index c584d0b54..b027ac960 100644
--- a/packages/contracts/src/2.0.0/test/DummyERC721Receiver/DummyERC721Receiver.sol
+++ b/packages/contracts/src/2.0.0/test/DummyERC721Receiver/DummyERC721Receiver.sol
@@ -27,6 +27,7 @@ pragma solidity ^0.4.24;
import "../../tokens/ERC721Token/IERC721Receiver.sol";
+
contract DummyERC721Receiver is
IERC721Receiver
{
diff --git a/packages/contracts/src/2.0.0/test/DummyERC721Token/DummyERC721Token.sol b/packages/contracts/src/2.0.0/test/DummyERC721Token/DummyERC721Token.sol
index 78ea96447..de76f10c5 100644
--- a/packages/contracts/src/2.0.0/test/DummyERC721Token/DummyERC721Token.sol
+++ b/packages/contracts/src/2.0.0/test/DummyERC721Token/DummyERC721Token.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../../tokens/ERC721Token/ERC721Token.sol";
import "../../utils/Ownable/Ownable.sol";
+
contract DummyERC721Token is
Ownable,
ERC721Token
diff --git a/packages/contracts/src/2.0.0/test/ExchangeWrapper/ExchangeWrapper.sol b/packages/contracts/src/2.0.0/test/ExchangeWrapper/ExchangeWrapper.sol
index 5baaf6e5a..f20e2a944 100644
--- a/packages/contracts/src/2.0.0/test/ExchangeWrapper/ExchangeWrapper.sol
+++ b/packages/contracts/src/2.0.0/test/ExchangeWrapper/ExchangeWrapper.sol
@@ -22,9 +22,11 @@ pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/interfaces/IExchange.sol";
import "../../protocol/Exchange/libs/LibOrder.sol";
+
contract ExchangeWrapper {
// Exchange contract.
+ // solhint-disable-next-line var-name-mixedcase
IExchange EXCHANGE;
constructor (address _exchange)
diff --git a/packages/contracts/src/2.0.0/test/Mintable/Mintable.sol b/packages/contracts/src/2.0.0/test/Mintable/Mintable.sol
index a91bfee9e..bccb74ce8 100644
--- a/packages/contracts/src/2.0.0/test/Mintable/Mintable.sol
+++ b/packages/contracts/src/2.0.0/test/Mintable/Mintable.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../../tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol";
import "../../utils/SafeMath/SafeMath.sol";
+
/*
* Mintable
* Base contract that creates a mintable UnlimitedAllowanceToken
diff --git a/packages/contracts/src/2.0.0/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol b/packages/contracts/src/2.0.0/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
index 2ae69e0ef..be7fea7d3 100644
--- a/packages/contracts/src/2.0.0/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
+++ b/packages/contracts/src/2.0.0/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
+
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
function publicDispatchTransferFrom(
bytes memory assetData,
diff --git a/packages/contracts/src/2.0.0/test/TestAssetProxyOwner/TestAssetProxyOwner.sol b/packages/contracts/src/2.0.0/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
index 2abcd17a0..ddcc62f35 100644
--- a/packages/contracts/src/2.0.0/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
+++ b/packages/contracts/src/2.0.0/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
@@ -20,6 +20,7 @@ pragma solidity ^0.4.24;
import "../../protocol/AssetProxyOwner/AssetProxyOwner.sol";
+
contract TestAssetProxyOwner is
AssetProxyOwner
{
diff --git a/packages/contracts/src/2.0.0/test/TestLibBytes/TestLibBytes.sol b/packages/contracts/src/2.0.0/test/TestLibBytes/TestLibBytes.sol
index f45faaf36..f52f635e1 100644
--- a/packages/contracts/src/2.0.0/test/TestLibBytes/TestLibBytes.sol
+++ b/packages/contracts/src/2.0.0/test/TestLibBytes/TestLibBytes.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../../utils/LibBytes/LibBytes.sol";
+
contract TestLibBytes {
using LibBytes for bytes;
diff --git a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol
index 010080703..df8eb55ce 100644
--- a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol
+++ b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol
@@ -23,6 +23,7 @@ import "../../protocol/Exchange/libs/LibMath.sol";
import "../../protocol/Exchange/libs/LibOrder.sol";
import "../../protocol/Exchange/libs/LibFillResults.sol";
+
contract TestLibs is
LibMath,
LibOrder,
diff --git a/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol b/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol
index 0f84678cf..591ae3378 100644
--- a/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol
+++ b/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/MixinSignatureValidator.sol";
import "../../protocol/Exchange/MixinTransactions.sol";
+
contract TestSignatureValidator is
MixinSignatureValidator,
MixinTransactions
diff --git a/packages/contracts/src/2.0.0/test/TestValidator/TestValidator.sol b/packages/contracts/src/2.0.0/test/TestValidator/TestValidator.sol
index f9271bf7a..5076dedc9 100644
--- a/packages/contracts/src/2.0.0/test/TestValidator/TestValidator.sol
+++ b/packages/contracts/src/2.0.0/test/TestValidator/TestValidator.sol
@@ -20,11 +20,13 @@ pragma solidity ^0.4.24;
import "../../protocol/Exchange/interfaces/IValidator.sol";
+
contract TestValidator is
IValidator
{
// The single valid signer for this wallet.
+ // solhint-disable-next-line var-name-mixedcase
address VALID_SIGNER;
/// @dev constructs a new `TestValidator` with a single valid signer.
diff --git a/packages/contracts/src/2.0.0/test/TestWallet/TestWallet.sol b/packages/contracts/src/2.0.0/test/TestWallet/TestWallet.sol
index 17dee9e9c..07dfac588 100644
--- a/packages/contracts/src/2.0.0/test/TestWallet/TestWallet.sol
+++ b/packages/contracts/src/2.0.0/test/TestWallet/TestWallet.sol
@@ -21,6 +21,7 @@ pragma solidity ^0.4.24;
import "../../protocol/Exchange/interfaces/IWallet.sol";
import "../../utils/LibBytes/LibBytes.sol";
+
contract TestWallet is
IWallet
{
@@ -29,6 +30,7 @@ contract TestWallet is
string constant LENGTH_65_REQUIRED = "LENGTH_65_REQUIRED";
// The owner of this wallet.
+ // solhint-disable-next-line var-name-mixedcase
address WALLET_OWNER;
/// @dev constructs a new `TestWallet` with a single owner.
diff --git a/packages/contracts/src/2.0.0/test/Whitelist/Whitelist.sol b/packages/contracts/src/2.0.0/test/Whitelist/Whitelist.sol
index 8b52858b1..07bd7d531 100644
--- a/packages/contracts/src/2.0.0/test/Whitelist/Whitelist.sol
+++ b/packages/contracts/src/2.0.0/test/Whitelist/Whitelist.sol
@@ -23,6 +23,7 @@ import "../../protocol/Exchange/interfaces/IExchange.sol";
import "../../protocol/Exchange/libs/LibOrder.sol";
import "../../utils/Ownable/Ownable.sol";
+
contract Whitelist is
Ownable
{
@@ -35,15 +36,19 @@ contract Whitelist is
mapping (address => bool) public isWhitelisted;
// Exchange contract.
+ // solhint-disable-next-line var-name-mixedcase
IExchange EXCHANGE;
byte constant VALIDATOR_SIGNATURE_BYTE = "\x06";
+ // solhint-disable-next-line var-name-mixedcase
bytes TX_ORIGIN_SIGNATURE;
constructor (address _exchange)
public
{
+ // solhint-disable-next-line var-name-mixedcase
EXCHANGE = IExchange(_exchange);
+ // solhint-disable-next-line var-name-mixedcase
TX_ORIGIN_SIGNATURE = abi.encodePacked(address(this), VALIDATOR_SIGNATURE_BYTE);
}
diff --git a/packages/contracts/src/2.0.0/tokens/ERC20Token/ERC20Token.sol b/packages/contracts/src/2.0.0/tokens/ERC20Token/ERC20Token.sol
index b6961a6ec..59dc7d7bf 100644
--- a/packages/contracts/src/2.0.0/tokens/ERC20Token/ERC20Token.sol
+++ b/packages/contracts/src/2.0.0/tokens/ERC20Token/ERC20Token.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "./IERC20Token.sol";
+
contract ERC20Token is IERC20Token {
string constant INSUFFICIENT_BALANCE = "ERC20_INSUFFICIENT_BALANCE";
diff --git a/packages/contracts/src/2.0.0/tokens/ERC20Token/IERC20Token.sol b/packages/contracts/src/2.0.0/tokens/ERC20Token/IERC20Token.sol
index eb879b6a8..de4ed2af9 100644
--- a/packages/contracts/src/2.0.0/tokens/ERC20Token/IERC20Token.sol
+++ b/packages/contracts/src/2.0.0/tokens/ERC20Token/IERC20Token.sol
@@ -19,6 +19,7 @@
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
+
contract IERC20Token {
/// @notice send `value` token to `to` from `msg.sender`
diff --git a/packages/contracts/src/2.0.0/tokens/ERC721Token/ERC721Token.sol b/packages/contracts/src/2.0.0/tokens/ERC721Token/ERC721Token.sol
index 41ba149e3..defb506a8 100644
--- a/packages/contracts/src/2.0.0/tokens/ERC721Token/ERC721Token.sol
+++ b/packages/contracts/src/2.0.0/tokens/ERC721Token/ERC721Token.sol
@@ -29,6 +29,7 @@ import "./IERC721Token.sol";
import "./IERC721Receiver.sol";
import "../../utils/SafeMath/SafeMath.sol";
+
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
diff --git a/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Receiver.sol b/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Receiver.sol
index b0fff3c90..f72c75638 100644
--- a/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Receiver.sol
+++ b/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Receiver.sol
@@ -25,6 +25,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.4.24;
+
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
diff --git a/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Token.sol b/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Token.sol
index 345712d67..0d64ee861 100644
--- a/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Token.sol
+++ b/packages/contracts/src/2.0.0/tokens/ERC721Token/IERC721Token.sol
@@ -25,6 +25,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.4.24;
+
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
diff --git a/packages/contracts/src/2.0.0/tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol b/packages/contracts/src/2.0.0/tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol
index f62602ab3..845324e4e 100644
--- a/packages/contracts/src/2.0.0/tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol
+++ b/packages/contracts/src/2.0.0/tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "../ERC20Token/ERC20Token.sol";
+
contract UnlimitedAllowanceToken is ERC20Token {
uint256 constant MAX_UINT = 2**256 - 1;
diff --git a/packages/contracts/src/2.0.0/tokens/WETH9/WETH9.sol b/packages/contracts/src/2.0.0/tokens/WETH9/WETH9.sol
index 733ca414b..378a507b9 100644
--- a/packages/contracts/src/2.0.0/tokens/WETH9/WETH9.sol
+++ b/packages/contracts/src/2.0.0/tokens/WETH9/WETH9.sol
@@ -15,6 +15,7 @@
pragma solidity ^0.4.18;
+
contract WETH9 {
string public name = "Wrapped Ether";
string public symbol = "WETH";
diff --git a/packages/contracts/src/2.0.0/tokens/ZRXToken/ZRXToken.sol b/packages/contracts/src/2.0.0/tokens/ZRXToken/ZRXToken.sol
index 2e5b61e0b..ed0670072 100644
--- a/packages/contracts/src/2.0.0/tokens/ZRXToken/ZRXToken.sol
+++ b/packages/contracts/src/2.0.0/tokens/ZRXToken/ZRXToken.sol
@@ -20,6 +20,8 @@ pragma solidity ^0.4.11;
import { UnlimitedAllowanceToken_v1 as UnlimitedAllowanceToken } from "../../../1.0.0/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol";
+
+
contract ZRXToken is UnlimitedAllowanceToken {
uint8 constant public decimals = 18;
diff --git a/packages/contracts/src/2.0.0/utils/LibBytes/LibBytes.sol b/packages/contracts/src/2.0.0/utils/LibBytes/LibBytes.sol
index 78b1ddf7c..c2fff5efb 100644
--- a/packages/contracts/src/2.0.0/utils/LibBytes/LibBytes.sol
+++ b/packages/contracts/src/2.0.0/utils/LibBytes/LibBytes.sol
@@ -18,6 +18,7 @@
pragma solidity ^0.4.24;
+
library LibBytes {
using LibBytes for bytes;
diff --git a/packages/contracts/src/2.0.0/utils/Ownable/Ownable.sol b/packages/contracts/src/2.0.0/utils/Ownable/Ownable.sol
index 6f5761cc7..489793a95 100644
--- a/packages/contracts/src/2.0.0/utils/Ownable/Ownable.sol
+++ b/packages/contracts/src/2.0.0/utils/Ownable/Ownable.sol
@@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2;
import "./IOwnable.sol";
+
contract Ownable is IOwnable {
address public owner;
diff --git a/packages/contracts/src/2.0.0/utils/SafeMath/SafeMath.sol b/packages/contracts/src/2.0.0/utils/SafeMath/SafeMath.sol
index e137f6ca5..ec0a3fe76 100644
--- a/packages/contracts/src/2.0.0/utils/SafeMath/SafeMath.sol
+++ b/packages/contracts/src/2.0.0/utils/SafeMath/SafeMath.sol
@@ -1,6 +1,7 @@
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
+
contract SafeMath {
function safeMul(uint a, uint b)
internal
diff --git a/packages/contracts/test/asset_proxy/authorizable.ts b/packages/contracts/test/asset_proxy/authorizable.ts
index 5a0586c28..e99c6cee3 100644
--- a/packages/contracts/test/asset_proxy/authorizable.ts
+++ b/packages/contracts/test/asset_proxy/authorizable.ts
@@ -5,7 +5,7 @@ import * as chai from 'chai';
import { MixinAuthorizableContract } from '../../generated_contract_wrappers/mixin_authorizable';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
@@ -44,7 +44,7 @@ describe('Authorizable', () => {
});
describe('addAuthorizedAddress', () => {
it('should throw if not called by owner', async () => {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
RevertReason.OnlyContractOwner,
);
@@ -62,7 +62,7 @@ describe('Authorizable', () => {
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
RevertReason.TargetAlreadyAuthorized,
);
@@ -75,7 +75,7 @@ describe('Authorizable', () => {
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
from: notOwner,
}),
@@ -99,7 +99,7 @@ describe('Authorizable', () => {
});
it('should throw if owner attempts to remove an address that is not authorized', async () => {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
from: owner,
}),
@@ -115,7 +115,7 @@ describe('Authorizable', () => {
constants.AWAIT_TRANSACTION_MINED_MS,
);
const index = new BigNumber(0);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
from: notOwner,
}),
@@ -128,7 +128,7 @@ describe('Authorizable', () => {
constants.AWAIT_TRANSACTION_MINED_MS,
);
const index = new BigNumber(1);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
from: owner,
}),
@@ -137,7 +137,7 @@ describe('Authorizable', () => {
});
it('should throw if owner attempts to remove an address that is not authorized', async () => {
const index = new BigNumber(0);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
from: owner,
}),
@@ -156,7 +156,7 @@ describe('Authorizable', () => {
constants.AWAIT_TRANSACTION_MINED_MS,
);
const address1Index = new BigNumber(0);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
from: owner,
}),
diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
index fc1e53352..bf9f9bc3e 100644
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ b/packages/contracts/test/asset_proxy/proxies.ts
@@ -17,7 +17,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr
import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy';
import { IAssetProxyContract } from '../../generated_contract_wrappers/i_asset_proxy';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
@@ -184,7 +184,7 @@ describe('Asset Transfer Proxies', () => {
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Perform a transfer; expect this to fail.
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ await expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc20Proxy.address,
data,
@@ -205,7 +205,7 @@ describe('Asset Transfer Proxies', () => {
takerAddress,
amount,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ await expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc20Proxy.address,
data,
@@ -344,7 +344,7 @@ describe('Asset Transfer Proxies', () => {
erc20Proxy.address, // the ERC20 proxy does not have an ERC721 receiver
amount,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc721Proxy.address,
data,
@@ -369,7 +369,7 @@ describe('Asset Transfer Proxies', () => {
takerAddress,
amount,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc721Proxy.address,
data,
@@ -393,7 +393,7 @@ describe('Asset Transfer Proxies', () => {
takerAddress,
amount,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc721Proxy.address,
data,
@@ -421,7 +421,7 @@ describe('Asset Transfer Proxies', () => {
takerAddress,
amount,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc721Proxy.address,
data,
@@ -442,7 +442,7 @@ describe('Asset Transfer Proxies', () => {
takerAddress,
amount,
);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
to: erc721Proxy.address,
data,
diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts
index db56623f9..4e70893fc 100644
--- a/packages/contracts/test/exchange/core.ts
+++ b/packages/contracts/test/exchange/core.ts
@@ -14,7 +14,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr
import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy';
import { CancelContractEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
@@ -144,7 +144,7 @@ describe('Exchange core', () => {
const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
signedOrder.signature = invalidSigHex;
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
RevertReason.InvalidOrderSignature,
);
@@ -153,7 +153,7 @@ describe('Exchange core', () => {
it('should throw if no value is filled', async () => {
signedOrder = orderFactory.newSignedOrder();
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
RevertReason.OrderUnfillable,
);
@@ -167,7 +167,7 @@ describe('Exchange core', () => {
});
it('should throw if not sent by maker', async () => {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress),
RevertReason.InvalidMaker,
);
@@ -178,7 +178,7 @@ describe('Exchange core', () => {
makerAssetAmount: new BigNumber(0),
});
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
RevertReason.OrderUnfillable,
);
@@ -189,7 +189,7 @@ describe('Exchange core', () => {
takerAssetAmount: new BigNumber(0),
});
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
RevertReason.OrderUnfillable,
);
@@ -197,7 +197,7 @@ describe('Exchange core', () => {
it('should be able to cancel a full order', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
}),
@@ -222,7 +222,7 @@ describe('Exchange core', () => {
it('should throw if already cancelled', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
RevertReason.OrderUnfillable,
);
@@ -232,7 +232,7 @@ describe('Exchange core', () => {
signedOrder = orderFactory.newSignedOrder({
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
});
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
RevertReason.OrderUnfillable,
);
@@ -250,7 +250,7 @@ describe('Exchange core', () => {
});
const fillTakerAssetAmount2 = new BigNumber(1);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: fillTakerAssetAmount2,
}),
@@ -264,7 +264,7 @@ describe('Exchange core', () => {
const orderEpoch = new BigNumber(1);
await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
const lesserOrderEpoch = new BigNumber(0);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress),
RevertReason.InvalidNewOrderEpoch,
);
@@ -273,7 +273,7 @@ describe('Exchange core', () => {
it('should fail to set orderEpoch equal to existing orderEpoch', async () => {
const orderEpoch = new BigNumber(1);
await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress),
RevertReason.InvalidNewOrderEpoch,
);
@@ -363,7 +363,7 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
RevertReason.TransferFailed,
);
@@ -386,7 +386,7 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
RevertReason.TransferFailed,
);
@@ -409,7 +409,7 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
RevertReason.InvalidAmount,
);
@@ -432,7 +432,7 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
RevertReason.InvalidAmount,
);
@@ -449,7 +449,7 @@ describe('Exchange core', () => {
});
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
RevertReason.RoundingError,
);
@@ -475,7 +475,7 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
RevertReason.LengthGreaterThan131Required,
);
diff --git a/packages/contracts/test/exchange/dispatcher.ts b/packages/contracts/test/exchange/dispatcher.ts
index afbf958d9..94ada1ef2 100644
--- a/packages/contracts/test/exchange/dispatcher.ts
+++ b/packages/contracts/test/exchange/dispatcher.ts
@@ -14,7 +14,7 @@ import {
TestAssetProxyDispatcherContract,
} from '../../generated_contract_wrappers/test_asset_proxy_dispatcher';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
@@ -129,7 +129,7 @@ describe('AssetProxyDispatcher', () => {
txDefaults,
);
// Register new ERC20 Transfer Proxy contract
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, {
from: owner,
}),
@@ -138,7 +138,7 @@ describe('AssetProxyDispatcher', () => {
});
it('should throw if requesting address is not owner', async () => {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: notOwner }),
RevertReason.OnlyContractOwner,
);
@@ -210,7 +210,7 @@ describe('AssetProxyDispatcher', () => {
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
// Perform a transfer from makerAddress to takerAddress
const amount = new BigNumber(10);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
encodedAssetData,
makerAddress,
diff --git a/packages/contracts/test/exchange/fill_order.ts b/packages/contracts/test/exchange/fill_order.ts
index 22eb401d9..029bd66e2 100644
--- a/packages/contracts/test/exchange/fill_order.ts
+++ b/packages/contracts/test/exchange/fill_order.ts
@@ -65,14 +65,7 @@ describe('FillOrder Tests', () => {
describe('fillOrder', () => {
const test = (fillScenarios: FillScenario[]) => {
_.forEach(fillScenarios, fillScenario => {
- const orderScenario = fillScenario.orderScenario;
- const description = `Combinatorial OrderFill: ${orderScenario.feeRecipientScenario} ${
- orderScenario.makerAssetAmountScenario
- } ${orderScenario.takerAssetAmountScenario} ${orderScenario.makerFeeScenario} ${
- orderScenario.takerFeeScenario
- } ${orderScenario.expirationTimeSecondsScenario} ${orderScenario.makerAssetDataScenario} ${
- orderScenario.takerAssetDataScenario
- }`;
+ const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
it(description, async () => {
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts
index 0d07d156f..90406415f 100644
--- a/packages/contracts/test/exchange/match_orders.ts
+++ b/packages/contracts/test/exchange/match_orders.ts
@@ -12,7 +12,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr
import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy';
import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
@@ -602,7 +602,7 @@ describe('matchOrders', () => {
// Cancel left order
await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
// Match orders
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
RevertReason.OrderUnfillable,
);
@@ -627,7 +627,7 @@ describe('matchOrders', () => {
// Cancel right order
await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
// Match orders
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
RevertReason.OrderUnfillable,
);
@@ -650,7 +650,7 @@ describe('matchOrders', () => {
feeRecipientAddress: feeRecipientAddressRight,
});
// Match orders
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
RevertReason.NegativeSpreadRequired,
);
@@ -673,7 +673,7 @@ describe('matchOrders', () => {
feeRecipientAddress: feeRecipientAddressRight,
});
// Match orders
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
// We are assuming assetData fields of the right order are the
// reverse of the left order, rather than checking equality. This
@@ -702,7 +702,7 @@ describe('matchOrders', () => {
feeRecipientAddress: feeRecipientAddressRight,
});
// Match orders
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
RevertReason.InvalidOrderSignature,
);
diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts
index 1db7dfc6d..c44d22479 100644
--- a/packages/contracts/test/exchange/signature_validator.ts
+++ b/packages/contracts/test/exchange/signature_validator.ts
@@ -13,7 +13,7 @@ import { TestValidatorContract } from '../../generated_contract_wrappers/test_va
import { TestWalletContract } from '../../generated_contract_wrappers/test_wallet';
import { addressUtils } from '../utils/address_utils';
import { artifacts } from '../utils/artifacts';
-import { expectRevertOrOtherErrorAsync } from '../utils/assertions';
+import { expectContractCallFailed } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { LogDecoder } from '../utils/log_decoder';
@@ -101,7 +101,7 @@ describe('MixinSignatureValidator', () => {
it('should revert when signature is empty', async () => {
const emptySignature = '0x';
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
@@ -115,7 +115,7 @@ describe('MixinSignatureValidator', () => {
const unsupportedSignatureType = SignatureType.NSignatureTypes;
const unsupportedSignatureHex = `0x${unsupportedSignatureType}`;
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
@@ -128,7 +128,7 @@ describe('MixinSignatureValidator', () => {
it('should revert when SignatureType=Illegal', async () => {
const unsupportedSignatureHex = `0x${SignatureType.Illegal}`;
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
@@ -155,7 +155,7 @@ describe('MixinSignatureValidator', () => {
const signatureBuffer = Buffer.concat([fillerData, signatureType]);
const signatureHex = ethUtil.bufferToHex(signatureBuffer);
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
diff --git a/packages/contracts/test/exchange/transactions.ts b/packages/contracts/test/exchange/transactions.ts
index 4f8b49e0e..959d79517 100644
--- a/packages/contracts/test/exchange/transactions.ts
+++ b/packages/contracts/test/exchange/transactions.ts
@@ -11,7 +11,7 @@ import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
import { ExchangeWrapperContract } from '../../generated_contract_wrappers/exchange_wrapper';
import { WhitelistContract } from '../../generated_contract_wrappers/whitelist';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
@@ -134,7 +134,7 @@ describe('Exchange transactions', () => {
});
it('should throw if not called by specified sender', async () => {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.executeTransactionAsync(signedTx, takerAddress),
RevertReason.FailedExecution,
);
@@ -177,7 +177,7 @@ describe('Exchange transactions', () => {
it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.executeTransactionAsync(signedTx, senderAddress),
RevertReason.InvalidTxHash,
);
@@ -197,7 +197,7 @@ describe('Exchange transactions', () => {
});
it('should throw if not called by specified sender', async () => {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.executeTransactionAsync(signedTx, makerAddress),
RevertReason.FailedExecution,
);
@@ -205,7 +205,7 @@ describe('Exchange transactions', () => {
it('should cancel the order when signed by maker and called by sender', async () => {
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrderAsync(signedOrder, senderAddress),
RevertReason.OrderUnfillable,
);
@@ -250,7 +250,7 @@ describe('Exchange transactions', () => {
signedOrder.signature,
);
const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapperContract.fillOrder.sendTransactionAsync(
orderWithoutExchangeAddress,
takerAssetFillAmount,
@@ -370,7 +370,7 @@ describe('Exchange transactions', () => {
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
const takerAssetFillAmount = signedOrder.takerAssetAmount;
const salt = generatePseudoRandomSalt();
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
orderWithoutExchangeAddress,
takerAssetFillAmount,
@@ -392,7 +392,7 @@ describe('Exchange transactions', () => {
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
const takerAssetFillAmount = signedOrder.takerAssetAmount;
const salt = generatePseudoRandomSalt();
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
orderWithoutExchangeAddress,
takerAssetFillAmount,
diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts
index 7942f7695..69f374e46 100644
--- a/packages/contracts/test/exchange/wrapper.ts
+++ b/packages/contracts/test/exchange/wrapper.ts
@@ -12,7 +12,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr
import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy';
import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
import { artifacts } from '../utils/artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
@@ -174,7 +174,7 @@ describe('Exchange wrappers', () => {
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
});
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
RevertReason.OrderUnfillable,
);
@@ -187,7 +187,7 @@ describe('Exchange wrappers', () => {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
});
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
RevertReason.CompleteFillFailed,
);
@@ -500,7 +500,7 @@ describe('Exchange wrappers', () => {
await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
takerAssetFillAmounts,
}),
@@ -703,7 +703,7 @@ describe('Exchange wrappers', () => {
orderFactory.newSignedOrder(),
];
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
}),
@@ -921,7 +921,7 @@ describe('Exchange wrappers', () => {
orderFactory.newSignedOrder(),
];
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
}),
diff --git a/packages/contracts/test/libraries/lib_bytes.ts b/packages/contracts/test/libraries/lib_bytes.ts
index 963b51b8f..c80b61e19 100644
--- a/packages/contracts/test/libraries/lib_bytes.ts
+++ b/packages/contracts/test/libraries/lib_bytes.ts
@@ -9,7 +9,7 @@ import * as _ from 'lodash';
import { TestLibBytesContract } from '../../generated_contract_wrappers/test_lib_bytes';
import { artifacts } from '../utils/artifacts';
-import { expectRevertOrOtherErrorAsync } from '../utils/assertions';
+import { expectContractCallFailed } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
@@ -100,7 +100,7 @@ describe('LibBytes', () => {
describe('popLastByte', () => {
it('should revert if length is 0', async () => {
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicPopLastByte.callAsync(constants.NULL_BYTES),
RevertReason.LibBytesGreaterThanZeroLengthRequired,
);
@@ -116,7 +116,7 @@ describe('LibBytes', () => {
describe('popLast20Bytes', () => {
it('should revert if length is less than 20', async () => {
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicPopLast20Bytes.callAsync(byteArrayShorterThan20Bytes),
RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
);
@@ -184,7 +184,7 @@ describe('LibBytes', () => {
describe('deepCopyBytes', () => {
it('should revert if dest is shorter than source', async () => {
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicDeepCopyBytes.callAsync(byteArrayShorterThan32Bytes, byteArrayLongerThan32Bytes),
RevertReason.LibBytesGreaterOrEqualToSourceBytesLengthRequired,
);
@@ -237,7 +237,7 @@ describe('LibBytes', () => {
it('should fail if the byte array is too short to hold an address', async () => {
const shortByteArray = '0xabcdef';
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadAddress.callAsync(shortByteArray, offset),
RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
);
@@ -245,7 +245,7 @@ describe('LibBytes', () => {
it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
const byteArray = testAddress;
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadAddress.callAsync(byteArray, badOffset),
RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
);
@@ -281,7 +281,7 @@ describe('LibBytes', () => {
});
it('should fail if the byte array is too short to hold an address', async () => {
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteAddress.callAsync(byteArrayShorterThan20Bytes, offset, testAddress),
RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
);
@@ -289,7 +289,7 @@ describe('LibBytes', () => {
it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
const byteArray = byteArrayLongerThan32Bytes;
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteAddress.callAsync(byteArray, badOffset, testAddress),
RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
);
@@ -313,14 +313,14 @@ describe('LibBytes', () => {
});
it('should fail if the byte array is too short to hold a bytes32', async () => {
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytes32.callAsync(testBytes32, badOffset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -356,7 +356,7 @@ describe('LibBytes', () => {
});
it('should fail if the byte array is too short to hold a bytes32', async () => {
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteBytes32.callAsync(byteArrayShorterThan32Bytes, offset, testBytes32),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -364,7 +364,7 @@ describe('LibBytes', () => {
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
const byteArray = byteArrayLongerThan32Bytes;
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteBytes32.callAsync(byteArray, badOffset, testBytes32),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -392,7 +392,7 @@ describe('LibBytes', () => {
});
it('should fail if the byte array is too short to hold a uint256', async () => {
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -402,7 +402,7 @@ describe('LibBytes', () => {
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadUint256.callAsync(byteArray, badOffset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -442,7 +442,7 @@ describe('LibBytes', () => {
});
it('should fail if the byte array is too short to hold a uint256', async () => {
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteUint256.callAsync(byteArrayShorterThan32Bytes, offset, testUint256),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -450,7 +450,7 @@ describe('LibBytes', () => {
it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
const byteArray = byteArrayLongerThan32Bytes;
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteUint256.callAsync(byteArray, badOffset, testUint256),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -461,7 +461,7 @@ describe('LibBytes', () => {
// AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0'
it('should revert if byte array has a length < 4', async () => {
const byteArrayLessThan4Bytes = '0x010101';
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytes4.callAsync(byteArrayLessThan4Bytes, new BigNumber(0)),
RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
);
@@ -516,28 +516,28 @@ describe('LibBytes', () => {
it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
// The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read.
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, offset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
});
it('should fail if we store a nested byte array length, without a nested byte array', async () => {
const offset = new BigNumber(0);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytesWithLength.callAsync(testBytes32, offset),
RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, badOffset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => {
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicReadBytesWithLength.callAsync(testBytes32, badOffset),
RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
);
@@ -649,7 +649,7 @@ describe('LibBytes', () => {
it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
const offset = new BigNumber(0);
const emptyByteArray = ethUtil.bufferToHex(new Buffer(1));
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, offset, longData),
RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
);
@@ -657,7 +657,7 @@ describe('LibBytes', () => {
it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array)', async () => {
const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, badOffset, shortData),
RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
);
diff --git a/packages/contracts/test/multisig/asset_proxy_owner.ts b/packages/contracts/test/multisig/asset_proxy_owner.ts
index cde86dd46..16231dfcb 100644
--- a/packages/contracts/test/multisig/asset_proxy_owner.ts
+++ b/packages/contracts/test/multisig/asset_proxy_owner.ts
@@ -14,8 +14,9 @@ import { MixinAuthorizableContract } from '../../generated_contract_wrappers/mix
import { TestAssetProxyOwnerContract } from '../../generated_contract_wrappers/test_asset_proxy_owner';
import { artifacts } from '../utils/artifacts';
import {
- expectRevertOrAlwaysFailingTransactionAsync,
- expectRevertOrContractCallFailedAsync,
+ expectContractCallFailedWithoutReasonAsync,
+ expectContractCreationFailedWithoutReason,
+ expectTransactionFailedWithoutReasonAsync,
} from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
@@ -108,7 +109,7 @@ describe('AssetProxyOwner', () => {
});
it('should throw if a null address is included in assetProxyContracts', async () => {
const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectContractCreationFailedWithoutReason(
AssetProxyOwnerContract.deployFrom0xArtifactAsync(
artifacts.AssetProxyOwner,
provider,
@@ -150,7 +151,7 @@ describe('AssetProxyOwner', () => {
describe('registerAssetProxy', () => {
it('should throw if not called by multisig', async () => {
const isRegistered = true;
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
testAssetProxyOwner.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, {
from: owners[0],
}),
@@ -277,7 +278,7 @@ describe('AssetProxyOwner', () => {
);
const log = submitTxRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
- return expectRevertOrContractCallFailedAsync(
+ return expectContractCallFailedWithoutReasonAsync(
testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
);
});
@@ -312,7 +313,7 @@ describe('AssetProxyOwner', () => {
);
const log = submitTxRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
- return expectRevertOrContractCallFailedAsync(
+ return expectContractCallFailedWithoutReasonAsync(
testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
);
});
@@ -332,7 +333,7 @@ describe('AssetProxyOwner', () => {
const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
from: owners[1],
}),
@@ -354,7 +355,7 @@ describe('AssetProxyOwner', () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
from: owners[1],
}),
@@ -376,7 +377,7 @@ describe('AssetProxyOwner', () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
from: owners[1],
}),
@@ -433,7 +434,7 @@ describe('AssetProxyOwner', () => {
const isExecuted = tx[3];
expect(isExecuted).to.equal(true);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
from: owners[1],
}),
diff --git a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
index a746403d2..a7b99d867 100644
--- a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
+++ b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
@@ -8,7 +8,7 @@ import {
SubmissionContractEventArgs,
} from '../../generated_contract_wrappers/multi_sig_wallet_with_time_lock';
import { artifacts } from '../utils/artifacts';
-import { expectRevertOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { increaseTimeAndMineBlockAsync } from '../utils/increase_time';
@@ -67,7 +67,7 @@ describe('MultiSigWalletWithTimeLock', () => {
});
it('should throw when not called by wallet', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
);
});
@@ -78,7 +78,7 @@ describe('MultiSigWalletWithTimeLock', () => {
const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
);
});
@@ -147,7 +147,7 @@ describe('MultiSigWalletWithTimeLock', () => {
});
it('should throw if it has enough confirmations but is not past the time lock', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
);
});
diff --git a/packages/contracts/test/token_registry.ts b/packages/contracts/test/token_registry.ts
index 32f8cdee3..7cc43be9b 100644
--- a/packages/contracts/test/token_registry.ts
+++ b/packages/contracts/test/token_registry.ts
@@ -7,7 +7,7 @@ import * as _ from 'lodash';
import { TokenRegistryContract } from '../generated_contract_wrappers/token_registry';
import { artifacts } from './utils/artifacts';
-import { expectRevertOrAlwaysFailingTransactionAsync } from './utils/assertions';
+import { expectTransactionFailedWithoutReasonAsync } from './utils/assertions';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
import { TokenRegWrapper } from './utils/token_registry_wrapper';
@@ -75,7 +75,7 @@ describe('TokenRegistry', () => {
describe('addToken', () => {
it('should throw when not called by owner', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, notOwner));
+ return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(token1, notOwner));
});
it('should add token metadata when called by owner', async () => {
@@ -87,20 +87,18 @@ describe('TokenRegistry', () => {
it('should throw if token already exists', async () => {
await tokenRegWrapper.addTokenAsync(token1, owner);
- return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, owner));
+ return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(token1, owner));
});
it('should throw if token address is null', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(nullToken, owner));
+ return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(nullToken, owner));
});
it('should throw if name already exists', async () => {
await tokenRegWrapper.addTokenAsync(token1, owner);
const duplicateNameToken = _.assign({}, token2, { name: token1.name });
- return expectRevertOrAlwaysFailingTransactionAsync(
- tokenRegWrapper.addTokenAsync(duplicateNameToken, owner),
- );
+ return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner));
});
it('should throw if symbol already exists', async () => {
@@ -109,7 +107,7 @@ describe('TokenRegistry', () => {
symbol: token1.symbol,
});
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner),
);
});
@@ -136,7 +134,7 @@ describe('TokenRegistry', () => {
describe('setTokenName', () => {
it('should throw when not called by owner', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: notOwner }),
);
});
@@ -162,13 +160,13 @@ describe('TokenRegistry', () => {
it('should throw if the name already exists', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: owner }),
);
});
it('should throw if token does not exist', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.setTokenName.sendTransactionAsync(nullToken.address, token2.name, { from: owner }),
);
});
@@ -176,7 +174,7 @@ describe('TokenRegistry', () => {
describe('setTokenSymbol', () => {
it('should throw when not called by owner', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, {
from: notOwner,
}),
@@ -202,7 +200,7 @@ describe('TokenRegistry', () => {
it('should throw if the symbol already exists', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, {
from: owner,
}),
@@ -210,7 +208,7 @@ describe('TokenRegistry', () => {
});
it('should throw if token does not exist', async () => {
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.setTokenSymbol.sendTransactionAsync(nullToken.address, token2.symbol, {
from: owner,
}),
@@ -221,7 +219,7 @@ describe('TokenRegistry', () => {
describe('removeToken', () => {
it('should throw if not called by owner', async () => {
const index = new BigNumber(0);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.removeToken.sendTransactionAsync(token1.address, index, { from: notOwner }),
);
});
@@ -240,7 +238,7 @@ describe('TokenRegistry', () => {
it('should throw if token does not exist', async () => {
const index = new BigNumber(0);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.removeToken.sendTransactionAsync(nullToken.address, index, { from: owner }),
);
});
@@ -248,7 +246,7 @@ describe('TokenRegistry', () => {
it('should throw if token at given index does not match address', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner);
const incorrectIndex = new BigNumber(0);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
tokenReg.removeToken.sendTransactionAsync(token2.address, incorrectIndex, { from: owner }),
);
});
diff --git a/packages/contracts/test/tokens/ether_token.ts b/packages/contracts/test/tokens/ether_token.ts
index 25ef15595..a104fc915 100644
--- a/packages/contracts/test/tokens/ether_token.ts
+++ b/packages/contracts/test/tokens/ether_token.ts
@@ -5,7 +5,7 @@ import * as chai from 'chai';
import { WETH9Contract } from '../../generated_contract_wrappers/weth9';
import { artifacts } from '../utils/artifacts';
-import { expectInsufficientFundsAsync, expectRevertOrAlwaysFailingTransactionAsync } from '../utils/assertions';
+import { expectInsufficientFundsAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
@@ -74,7 +74,7 @@ describe('EtherToken', () => {
const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
const ethTokensToWithdraw = initEthTokenBalance.plus(1);
- return expectRevertOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedWithoutReasonAsync(
etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw),
);
});
diff --git a/packages/contracts/test/tokens/unlimited_allowance_token.ts b/packages/contracts/test/tokens/unlimited_allowance_token.ts
index 09a24950c..8a3b20d0f 100644
--- a/packages/contracts/test/tokens/unlimited_allowance_token.ts
+++ b/packages/contracts/test/tokens/unlimited_allowance_token.ts
@@ -5,7 +5,7 @@ import * as chai from 'chai';
import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token';
import { artifacts } from '../utils/artifacts';
-import { expectRevertOrOtherErrorAsync } from '../utils/assertions';
+import { expectContractCallFailed } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
@@ -54,7 +54,7 @@ describe('UnlimitedAllowanceToken', () => {
it('should throw if owner has insufficient balance', async () => {
const ownerBalance = await token.balanceOf.callAsync(owner);
const amountToTransfer = ownerBalance.plus(1);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
token.transfer.callAsync(spender, amountToTransfer, { from: owner }),
RevertReason.Erc20InsufficientBalance,
);
@@ -93,7 +93,7 @@ describe('UnlimitedAllowanceToken', () => {
await token.approve.sendTransactionAsync(spender, amountToTransfer, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
from: spender,
}),
@@ -109,7 +109,7 @@ describe('UnlimitedAllowanceToken', () => {
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(isSpenderAllowanceInsufficient).to.be.true();
- return expectRevertOrOtherErrorAsync(
+ return expectContractCallFailed(
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
from: spender,
}),
diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts
index baba892d3..112a470f6 100644
--- a/packages/contracts/test/utils/assertions.ts
+++ b/packages/contracts/test/utils/assertions.ts
@@ -1,108 +1,159 @@
import { RevertReason } from '@0xproject/types';
+import { logUtils } from '@0xproject/utils';
+import { NodeType } from '@0xproject/web3-wrapper';
import * as chai from 'chai';
-import { TransactionReceipt, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
+import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
-import { constants } from './constants';
import { web3Wrapper } from './web3_wrapper';
const expect = chai.expect;
-function _expectEitherErrorAsync<T>(p: Promise<T>, error1: string, error2: string): PromiseLike<void> {
- return expect(p)
- .to.be.rejected()
- .then(e => {
- expect(e).to.satisfy(
- (err: Error) => _.includes(err.message, error1) || _.includes(err.message, error2),
- `expected promise to reject with error message that includes "${error1}" or "${error2}", but got: ` +
- `"${e.message}"\n`,
- );
- });
+let nodeType: NodeType | undefined;
+
+// Represents the return value of a `sendTransaction` call. The Promise should
+// resolve with either a transaction receipt or a transaction hash.
+export type sendTransactionResult = Promise<TransactionReceipt | TransactionReceiptWithDecodedLogs | string>;
+
+async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise<string> {
+ if (_.isUndefined(nodeType)) {
+ nodeType = await web3Wrapper.getNodeTypeAsync();
+ }
+ switch (nodeType) {
+ case NodeType.Ganache:
+ return ganacheError;
+ case NodeType.Geth:
+ return gethError;
+ default:
+ throw new Error(`Unknown node type: ${nodeType}`);
+ }
+}
+
+async function _getInsufficientFundsErrorMessageAsync(): Promise<string> {
+ return _getGanacheOrGethError("sender doesn't have enough funds", 'insufficient funds');
+}
+
+async function _getTransactionFailedErrorMessageAsync(): Promise<string> {
+ return _getGanacheOrGethError('revert', 'always failing transaction');
+}
+
+async function _getContractCallFailedErrorMessageAsync(): Promise<string> {
+ return _getGanacheOrGethError('revert', 'Contract call failed');
}
/**
* Rejects if the given Promise does not reject with an error indicating
* insufficient funds.
- * @param p the Promise which is expected to reject
+ * @param p a promise resulting from a contract call or sendTransaction call.
* @returns a new Promise which will reject if the conditions are not met and
* otherwise resolve with no value.
*/
-export function expectInsufficientFundsAsync<T>(p: Promise<T>): PromiseLike<void> {
- return _expectEitherErrorAsync(p, 'insufficient funds', "sender doesn't have enough funds");
+export async function expectInsufficientFundsAsync<T>(p: Promise<T>): Promise<void> {
+ const errMessage = await _getInsufficientFundsErrorMessageAsync();
+ return expect(p).to.be.rejectedWith(errMessage);
}
/**
- * Rejects if the given Promise does not reject with a "revert" error or the
- * given otherError.
- * @param p the Promise which is expected to reject
- * @param otherError the other error which is accepted as a valid reject error.
+ * Resolves if the the sendTransaction call fails with the given revert reason.
+ * However, since Geth does not support revert reasons for sendTransaction, this
+ * falls back to expectTransactionFailedWithoutReasonAsync if the backing
+ * Ethereum node is Geth.
+ * @param p a Promise resulting from a sendTransaction call
+ * @param reason a specific revert reason
* @returns a new Promise which will reject if the conditions are not met and
* otherwise resolve with no value.
*/
-export function expectRevertOrOtherErrorAsync<T>(p: Promise<T>, otherError: string): PromiseLike<void> {
- return _expectEitherErrorAsync(p, constants.REVERT, otherError);
-}
+export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise<void> {
+ // HACK(albrow): This dummy `catch` should not be necessary, but if you
+ // remove it, there is an uncaught exception and the Node process will
+ // forcibly exit. It's possible this is a false positive in
+ // make-promises-safe.
+ p.catch(e => {
+ _.noop(e);
+ });
-/**
- * Rejects if the given Promise does not reject with a "revert" or "always
- * failing transaction" error.
- * @param p the Promise which is expected to reject
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export function expectRevertOrAlwaysFailingTransactionAsync<T>(p: Promise<T>): PromiseLike<void> {
- return expectRevertOrOtherErrorAsync(p, 'always failing transaction');
+ if (_.isUndefined(nodeType)) {
+ nodeType = await web3Wrapper.getNodeTypeAsync();
+ }
+ switch (nodeType) {
+ case NodeType.Ganache:
+ return expect(p).to.be.rejectedWith(reason);
+ case NodeType.Geth:
+ logUtils.warn(
+ 'WARNING: Geth does not support revert reasons for sendTransaction. This test will pass if the transaction fails for any reason.',
+ );
+ return expectTransactionFailedWithoutReasonAsync(p);
+ default:
+ throw new Error(`Unknown node type: ${nodeType}`);
+ }
}
/**
- * Rejects if at least one the following conditions is not met:
- * 1) The given Promise rejects with the given revert reason.
- * 2) The given Promise rejects with an error containing "always failing transaction"
- * 3) The given Promise fulfills with a txReceipt that has a status of 0 or '0', indicating the transaction failed.
- * 4) The given Promise fulfills with a txHash and corresponding txReceipt has a status of 0 or '0'.
- * @param p the Promise which is expected to reject
- * @param reason a specific revert reason
+ * Resolves if the transaction fails without a revert reason, or if the
+ * corresponding transactionReceipt has a status of 0 or '0', indicating
+ * failure.
+ * @param p a Promise resulting from a sendTransaction call
* @returns a new Promise which will reject if the conditions are not met and
* otherwise resolve with no value.
*/
-export async function expectRevertReasonOrAlwaysFailingTransactionAsync(
- p: Promise<string | TransactionReceiptWithDecodedLogs | TransactionReceipt>,
- reason: RevertReason,
-): Promise<void> {
+export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise<void> {
return p
.then(async result => {
- let txReceiptStatus: string | 0 | 1 | null;
- if (typeof result === 'string') {
- // Result is a txHash. We need to make a web3 call to get the receipt.
+ let txReceiptStatus: TransactionReceiptStatus;
+ if (_.isString(result)) {
+ // Result is a txHash. We need to make a web3 call to get the
+ // receipt, then get the status from the receipt.
const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(result);
txReceiptStatus = txReceipt.status;
} else if ('status' in result) {
- // Result is a TransactionReceiptWithDecodedLogs or TransactionReceipt
- // and status is a field of result.
+ // Result is a transaction receipt, so we can get the status
+ // directly.
txReceiptStatus = result.status;
} else {
- throw new Error('Unexpected result type');
+ throw new Error('Unexpected result type: ' + typeof result);
}
expect(_.toString(txReceiptStatus)).to.equal(
'0',
- 'transactionReceipt had a non-zero status, indicating success',
+ 'Expected transaction to fail but receipt had a non-zero status, indicating success',
);
})
- .catch(err => {
- expect(err.message).to.satisfy(
- (msg: string) => _.includes(msg, reason) || _.includes(msg, 'always failing transaction'),
- `Expected ${reason} or 'always failing transaction' but error message was ${err.message}`,
- );
+ .catch(async err => {
+ // If the promise rejects, we expect a specific error message,
+ // depending on the backing Ethereum node type.
+ const errMessage = await _getTransactionFailedErrorMessageAsync();
+ expect(err.message).to.include(errMessage);
});
}
/**
- * Rejects if the given Promise does not reject with a "revert" or "Contract
- * call failed" error.
- * @param p the Promise which is expected to reject
+ * Resolves if the the contract call fails with the given revert reason.
+ * @param p a Promise resulting from a contract call
+ * @param reason a specific revert reason
+ * @returns a new Promise which will reject if the conditions are not met and
+ * otherwise resolve with no value.
+ */
+export async function expectContractCallFailed<T>(p: Promise<T>, reason: RevertReason): Promise<void> {
+ return expect(p).to.be.rejectedWith(reason);
+}
+
+/**
+ * Resolves if the contract call fails without a revert reason.
+ * @param p a Promise resulting from a contract call
+ * @returns a new Promise which will reject if the conditions are not met and
+ * otherwise resolve with no value.
+ */
+export async function expectContractCallFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> {
+ const errMessage = await _getContractCallFailedErrorMessageAsync();
+ return expect(p).to.be.rejectedWith(errMessage);
+}
+
+/**
+ * Resolves if the contract creation/deployment fails without a revert reason.
+ * @param p a Promise resulting from a contract creation/deployment
* @returns a new Promise which will reject if the conditions are not met and
* otherwise resolve with no value.
*/
-export function expectRevertOrContractCallFailedAsync<T>(p: Promise<T>): PromiseLike<void> {
- return expectRevertOrOtherErrorAsync<T>(p, 'Contract call failed');
+export async function expectContractCreationFailedWithoutReason<T>(p: Promise<T>): Promise<void> {
+ const errMessage = await _getTransactionFailedErrorMessageAsync();
+ return expect(p).to.be.rejectedWith(errMessage);
}
diff --git a/packages/contracts/test/utils/asset_wrapper.ts b/packages/contracts/test/utils/asset_wrapper.ts
index 402a7ab28..f291170a2 100644
--- a/packages/contracts/test/utils/asset_wrapper.ts
+++ b/packages/contracts/test/utils/asset_wrapper.ts
@@ -84,8 +84,15 @@ export class AssetWrapper {
userAddress,
);
} else if (tokenOwner === userAddress && desiredBalance.eq(0)) {
- // Burn token
- await erc721Wrapper.burnAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress);
+ // Transfer token to someone else
+ const userAddresses = await (erc721Wrapper as any)._web3Wrapper.getAvailableAddressesAsync();
+ const nonOwner = _.find(userAddresses, a => a !== userAddress);
+ await erc721Wrapper.transferFromAsync(
+ assetProxyData.tokenAddress,
+ assetProxyData.tokenId,
+ tokenOwner,
+ nonOwner,
+ );
return;
} else if (
(userAddress !== tokenOwner && desiredBalance.eq(0)) ||
diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts
index 8e68f376d..7f3ad62e1 100644
--- a/packages/contracts/test/utils/constants.ts
+++ b/packages/contracts/test/utils/constants.ts
@@ -18,7 +18,6 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [
export const constants = {
INVALID_OPCODE: 'invalid opcode',
- REVERT: 'revert',
TESTRPC_NETWORK_ID: 50,
// Note(albrow): In practice V8 and most other engines limit the minimum
// interval for setInterval to 10ms. We still set it to 0 here in order to
diff --git a/packages/contracts/test/utils/core_combinatorial_utils.ts b/packages/contracts/test/utils/core_combinatorial_utils.ts
index 718be17e0..8c6c83014 100644
--- a/packages/contracts/test/utils/core_combinatorial_utils.ts
+++ b/packages/contracts/test/utils/core_combinatorial_utils.ts
@@ -17,7 +17,7 @@ import 'make-promises-safe';
import { ExchangeContract, FillContractEventArgs } from '../../generated_contract_wrappers/exchange';
import { artifacts } from './artifacts';
-import { expectRevertReasonOrAlwaysFailingTransactionAsync } from './assertions';
+import { expectTransactionFailedAsync } from './assertions';
import { AssetWrapper } from './asset_wrapper';
import { chaiSetup } from './chai_setup';
import { constants } from './constants';
@@ -75,7 +75,7 @@ export async function coreCombinatorialUtilsFactoryAsync(
const zrxAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
const erc20FiveDecimalTokenCount = 2;
- const fiveDecimals = new BigNumber(18);
+ const fiveDecimals = new BigNumber(5);
const [erc20FiveDecimalTokenA, erc20FiveDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
erc20FiveDecimalTokenCount,
fiveDecimals,
@@ -146,13 +146,39 @@ export class CoreCombinatorialUtils {
public exchangeWrapper: ExchangeWrapper;
public assetWrapper: AssetWrapper;
public static generateFillOrderCombinations(): FillScenario[] {
- const takerScenarios = [TakerScenario.Unspecified];
- const feeRecipientScenarios = [FeeRecipientAddressScenario.EthUserAddress];
- const makerAssetAmountScenario = [OrderAssetAmountScenario.Large];
- const takerAssetAmountScenario = [OrderAssetAmountScenario.Large];
- const makerFeeScenario = [OrderAssetAmountScenario.Large];
- const takerFeeScenario = [OrderAssetAmountScenario.Large];
- const expirationTimeSecondsScenario = [ExpirationTimeSecondsScenario.InFuture];
+ const takerScenarios = [
+ TakerScenario.Unspecified,
+ // TakerScenario.CorrectlySpecified,
+ // TakerScenario.IncorrectlySpecified,
+ ];
+ const feeRecipientScenarios = [
+ FeeRecipientAddressScenario.EthUserAddress,
+ // FeeRecipientAddressScenario.BurnAddress,
+ ];
+ const makerAssetAmountScenario = [
+ OrderAssetAmountScenario.Large,
+ // OrderAssetAmountScenario.Zero,
+ // OrderAssetAmountScenario.Small,
+ ];
+ const takerAssetAmountScenario = [
+ OrderAssetAmountScenario.Large,
+ // OrderAssetAmountScenario.Zero,
+ // OrderAssetAmountScenario.Small,
+ ];
+ const makerFeeScenario = [
+ OrderAssetAmountScenario.Large,
+ // OrderAssetAmountScenario.Small,
+ // OrderAssetAmountScenario.Zero,
+ ];
+ const takerFeeScenario = [
+ OrderAssetAmountScenario.Large,
+ // OrderAssetAmountScenario.Small,
+ // OrderAssetAmountScenario.Zero,
+ ];
+ const expirationTimeSecondsScenario = [
+ ExpirationTimeSecondsScenario.InFuture,
+ ExpirationTimeSecondsScenario.InPast,
+ ];
const makerAssetDataScenario = [
AssetDataScenario.ERC20FiveDecimals,
AssetDataScenario.ERC20NonZRXEighteenDecimals,
@@ -165,7 +191,55 @@ export class CoreCombinatorialUtils {
AssetDataScenario.ERC721,
AssetDataScenario.ZRXFeeToken,
];
- const takerAssetFillAmountScenario = [TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount];
+ const takerAssetFillAmountScenario = [
+ TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
+ // TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
+ // TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
+ ];
+ const makerAssetBalanceScenario = [
+ BalanceAmountScenario.Higher,
+ // BalanceAmountScenario.Exact,
+ // BalanceAmountScenario.TooLow,
+ ];
+ const makerAssetAllowanceScenario = [
+ AllowanceAmountScenario.Higher,
+ // AllowanceAmountScenario.Exact,
+ // AllowanceAmountScenario.TooLow,
+ // AllowanceAmountScenario.Unlimited,
+ ];
+ const makerZRXBalanceScenario = [
+ BalanceAmountScenario.Higher,
+ // BalanceAmountScenario.Exact,
+ // BalanceAmountScenario.TooLow,
+ ];
+ const makerZRXAllowanceScenario = [
+ AllowanceAmountScenario.Higher,
+ // AllowanceAmountScenario.Exact,
+ // AllowanceAmountScenario.TooLow,
+ // AllowanceAmountScenario.Unlimited,
+ ];
+ const takerAssetBalanceScenario = [
+ BalanceAmountScenario.Higher,
+ // BalanceAmountScenario.Exact,
+ // BalanceAmountScenario.TooLow,
+ ];
+ const takerAssetAllowanceScenario = [
+ AllowanceAmountScenario.Higher,
+ // AllowanceAmountScenario.Exact,
+ // AllowanceAmountScenario.TooLow,
+ // AllowanceAmountScenario.Unlimited,
+ ];
+ const takerZRXBalanceScenario = [
+ BalanceAmountScenario.Higher,
+ // BalanceAmountScenario.Exact,
+ // BalanceAmountScenario.TooLow,
+ ];
+ const takerZRXAllowanceScenario = [
+ AllowanceAmountScenario.Higher,
+ // AllowanceAmountScenario.Exact,
+ // AllowanceAmountScenario.TooLow,
+ // AllowanceAmountScenario.Unlimited,
+ ];
const fillScenarioArrays = CoreCombinatorialUtils._getAllCombinations([
takerScenarios,
feeRecipientScenarios,
@@ -177,9 +251,18 @@ export class CoreCombinatorialUtils {
makerAssetDataScenario,
takerAssetDataScenario,
takerAssetFillAmountScenario,
+ makerAssetBalanceScenario,
+ makerAssetAllowanceScenario,
+ makerZRXBalanceScenario,
+ makerZRXAllowanceScenario,
+ takerAssetBalanceScenario,
+ takerAssetAllowanceScenario,
+ takerZRXBalanceScenario,
+ takerZRXAllowanceScenario,
]);
const fillScenarios = _.map(fillScenarioArrays, fillScenarioArray => {
+ // tslint:disable:custom-no-magic-numbers
const fillScenario: FillScenario = {
orderScenario: {
takerScenario: fillScenarioArray[0] as TakerScenario,
@@ -194,18 +277,19 @@ export class CoreCombinatorialUtils {
},
takerAssetFillAmountScenario: fillScenarioArray[9] as TakerAssetFillAmountScenario,
makerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
+ traderAssetBalance: fillScenarioArray[10] as BalanceAmountScenario,
+ traderAssetAllowance: fillScenarioArray[11] as AllowanceAmountScenario,
+ zrxFeeBalance: fillScenarioArray[12] as BalanceAmountScenario,
+ zrxFeeAllowance: fillScenarioArray[13] as AllowanceAmountScenario,
},
takerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
+ traderAssetBalance: fillScenarioArray[14] as BalanceAmountScenario,
+ traderAssetAllowance: fillScenarioArray[15] as AllowanceAmountScenario,
+ zrxFeeBalance: fillScenarioArray[16] as BalanceAmountScenario,
+ zrxFeeAllowance: fillScenarioArray[17] as AllowanceAmountScenario,
},
};
+ // tslint:enable:custom-no-magic-numbers
return fillScenario;
});
@@ -334,7 +418,7 @@ export class CoreCombinatorialUtils {
fillRevertReasonIfExists: RevertReason | undefined,
): Promise<void> {
if (!_.isUndefined(fillRevertReasonIfExists)) {
- return expectRevertReasonOrAlwaysFailingTransactionAsync(
+ return expectTransactionFailedAsync(
this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }),
fillRevertReasonIfExists,
);
@@ -768,25 +852,17 @@ export class CoreCombinatorialUtils {
case AllowanceAmountScenario.TooLow:
const tooLowAllowance = takerFee.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.takerAddress,
- this.zrxAssetData,
- tooLowAllowance,
- );
+ await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, tooLowAllowance);
break;
case AllowanceAmountScenario.Exact:
const exactAllowance = takerFee;
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.takerAddress,
- this.zrxAssetData,
- exactAllowance,
- );
+ await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, exactAllowance);
break;
case AllowanceAmountScenario.Unlimited:
await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.takerAddress,
+ this.takerAddress,
this.zrxAssetData,
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
);
diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json
index e62075054..15f8d6ab0 100644
--- a/packages/dev-utils/package.json
+++ b/packages/dev-utils/package.json
@@ -48,12 +48,11 @@
"@0xproject/subproviders": "^0.10.4",
"@0xproject/types": "^0.8.1",
"@0xproject/utils": "^0.7.1",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/web3-wrapper": "^0.7.1",
"lodash": "^4.17.4",
- "web3": "^0.20.0",
- "web3-provider-engine": "^14.0.4"
+ "web3-provider-engine": "14.0.6"
},
"publishConfig": {
"access": "public"
diff --git a/packages/dev-utils/src/blockchain_lifecycle.ts b/packages/dev-utils/src/blockchain_lifecycle.ts
index 587332f1a..9bd65ee5d 100644
--- a/packages/dev-utils/src/blockchain_lifecycle.ts
+++ b/packages/dev-utils/src/blockchain_lifecycle.ts
@@ -1,11 +1,6 @@
import { logUtils } from '@0xproject/utils';
-import { uniqueVersionIds, Web3Wrapper } from '@0xproject/web3-wrapper';
-import { includes } from 'lodash';
-
-enum NodeType {
- Geth = 'GETH',
- Ganache = 'GANACHE',
-}
+import { NodeType, Web3Wrapper } from '@0xproject/web3-wrapper';
+import * as _ from 'lodash';
// HACK(albrow): 🐉 We have to do this so that debug.setHead works correctly.
// (Geth does not seem to like debug.setHead(0), so by sending some transactions
@@ -18,6 +13,7 @@ export class BlockchainLifecycle {
private _web3Wrapper: Web3Wrapper;
private _snapshotIdsStack: number[];
private _addresses: string[] = [];
+ private _nodeType: NodeType | undefined;
constructor(web3Wrapper: Web3Wrapper) {
this._web3Wrapper = web3Wrapper;
this._snapshotIdsStack = [];
@@ -61,16 +57,6 @@ export class BlockchainLifecycle {
throw new Error(`Unknown node type: ${nodeType}`);
}
}
- private async _getNodeTypeAsync(): Promise<NodeType> {
- const version = await this._web3Wrapper.getNodeVersionAsync();
- if (includes(version, uniqueVersionIds.geth)) {
- return NodeType.Geth;
- } else if (includes(version, uniqueVersionIds.ganache)) {
- return NodeType.Ganache;
- } else {
- throw new Error(`Unknown client version: ${version}`);
- }
- }
private async _mineMinimumBlocksAsync(): Promise<void> {
logUtils.warn('WARNING: minimum block number for tests not met. Mining additional blocks...');
if (this._addresses.length === 0) {
@@ -92,4 +78,10 @@ export class BlockchainLifecycle {
}
logUtils.warn('Done mining the minimum number of blocks.');
}
+ private async _getNodeTypeAsync(): Promise<NodeType> {
+ if (_.isUndefined(this._nodeType)) {
+ this._nodeType = await this._web3Wrapper.getNodeTypeAsync();
+ }
+ return this._nodeType;
+ }
}
diff --git a/packages/dev-utils/src/web3_factory.ts b/packages/dev-utils/src/web3_factory.ts
index 47eef4cbd..362a6c3c6 100644
--- a/packages/dev-utils/src/web3_factory.ts
+++ b/packages/dev-utils/src/web3_factory.ts
@@ -1,8 +1,3 @@
-// HACK: web3 injects XMLHttpRequest into the global scope and ProviderEngine checks XMLHttpRequest
-// to know whether it is running in a browser or node environment. We need it to be undefined since
-// we are not running in a browser env.
-// Filed issue: https://github.com/ethereum/web3.js/issues/844
-(global as any).XMLHttpRequest = undefined;
import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
diff --git a/packages/ethereum-types/CHANGELOG.json b/packages/ethereum-types/CHANGELOG.json
index ad532062f..351e9c23f 100644
--- a/packages/ethereum-types/CHANGELOG.json
+++ b/packages/ethereum-types/CHANGELOG.json
@@ -5,6 +5,10 @@
{
"note": "Add `TraceParams` interface for `debug_traceTransaction` parameters",
"pr": 675
+ },
+ {
+ "note": "Add `TransactionReceiptStatus` type",
+ "pr": 812
}
]
},
diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json
index a937f6ad1..9d4930826 100644
--- a/packages/ethereum-types/package.json
+++ b/packages/ethereum-types/package.json
@@ -1,6 +1,6 @@
{
"name": "ethereum-types",
- "version": "0.0.1",
+ "version": "0.0.2",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/ethereum-types/src/index.ts b/packages/ethereum-types/src/index.ts
index 499c84327..f4d445e3b 100644
--- a/packages/ethereum-types/src/index.ts
+++ b/packages/ethereum-types/src/index.ts
@@ -215,6 +215,8 @@ export interface TxDataPayable extends TxData {
value?: BigNumber;
}
+export type TransactionReceiptStatus = null | string | 0 | 1;
+
export interface TransactionReceipt {
blockHash: string;
blockNumber: number;
@@ -222,7 +224,7 @@ export interface TransactionReceipt {
transactionIndex: number;
from: string;
to: string;
- status: null | string | 0 | 1;
+ status: TransactionReceiptStatus;
cumulativeGasUsed: number;
gasUsed: number;
contractAddress: string | null;
diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json
index ec9111ebb..822f8d5d5 100644
--- a/packages/fill-scenarios/CHANGELOG.json
+++ b/packages/fill-scenarios/CHANGELOG.json
@@ -1,6 +1,6 @@
[
{
- "version": "0.1.0",
+ "version": "1.0.0",
"changes": [
{
"note": "Make fill-scenarios compatible with V2 of 0x protocol",
diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json
index 883300fa0..91024ed34 100644
--- a/packages/fill-scenarios/package.json
+++ b/packages/fill-scenarios/package.json
@@ -44,7 +44,7 @@
"@0xproject/base-contract": "^0.3.4",
"@0xproject/order-utils": "^1.0.0",
"@0xproject/types": "1.0.0",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json
index bb9cd3cd2..dfefdfc77 100644
--- a/packages/json-schemas/CHANGELOG.json
+++ b/packages/json-schemas/CHANGELOG.json
@@ -1,5 +1,18 @@
[
{
+ "version": "1.0.0",
+ "changes": [
+ {
+ "note": "Update schemas for V2",
+ "pr": 615
+ },
+ {
+ "note": "Added CallData schema",
+ "pr": 821
+ }
+ ]
+ },
+ {
"timestamp": 1529397769,
"version": "0.8.1",
"changes": [
diff --git a/packages/json-schemas/schemas/call_data_schema.ts b/packages/json-schemas/schemas/call_data_schema.ts
new file mode 100644
index 000000000..e8fcc7512
--- /dev/null
+++ b/packages/json-schemas/schemas/call_data_schema.ts
@@ -0,0 +1,27 @@
+export const callDataSchema = {
+ id: '/TxData',
+ properties: {
+ from: { $ref: '/Address' },
+ to: { $ref: '/Address' },
+ value: {
+ oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
+ },
+ gas: {
+ oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
+ },
+ gasPrice: {
+ oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
+ },
+ data: {
+ type: 'string',
+ pattern: '^0x[0-9a-f]*$',
+ },
+ nonce: {
+ type: 'number',
+ minimum: 0,
+ },
+ },
+ required: [],
+ type: 'object',
+ additionalProperties: false,
+};
diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts
index 77ea88f5c..4e13aeafb 100644
--- a/packages/json-schemas/src/schemas.ts
+++ b/packages/json-schemas/src/schemas.ts
@@ -1,5 +1,6 @@
import { addressSchema, hexSchema, numberSchema } from '../schemas/basic_type_schemas';
import { blockParamSchema, blockRangeSchema } from '../schemas/block_range_schema';
+import { callDataSchema } from '../schemas/call_data_schema';
import { ecSignatureSchema } from '../schemas/ec_signature_schema';
import { indexFilterValuesSchema } from '../schemas/index_filter_values_schema';
import { orderCancellationRequestsSchema } from '../schemas/order_cancel_schema';
@@ -31,6 +32,7 @@ import { jsNumber, txDataSchema } from '../schemas/tx_data_schema';
export const schemas = {
numberSchema,
addressSchema,
+ callDataSchema,
hexSchema,
ecSignatureSchema,
indexFilterValuesSchema,
diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json
index 6b6ab9c40..3fa79387e 100644
--- a/packages/metacoin/package.json
+++ b/packages/metacoin/package.json
@@ -45,7 +45,7 @@
"ethers": "3.0.22",
"lodash": "^4.17.4",
"run-s": "^0.0.0",
- "web3-provider-engine": "^14.0.4"
+ "web3-provider-engine": "14.0.6"
},
"devDependencies": {
"@0xproject/dev-utils": "^0.4.4",
diff --git a/packages/migrations/package.json b/packages/migrations/package.json
index 979e526d2..32accb57a 100644
--- a/packages/migrations/package.json
+++ b/packages/migrations/package.json
@@ -58,10 +58,10 @@
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
"@ledgerhq/hw-app-eth": "^4.3.0",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"ethers": "3.0.22",
"lodash": "^4.17.4",
- "web3-provider-engine": "^14.0.4"
+ "web3-provider-engine": "14.0.6"
},
"optionalDependencies": {
"@ledgerhq/hw-transport-node-hid": "^4.3.0"
diff --git a/packages/monorepo-scripts/CHANGELOG.json b/packages/monorepo-scripts/CHANGELOG.json
index a1dda0176..781704a8e 100644
--- a/packages/monorepo-scripts/CHANGELOG.json
+++ b/packages/monorepo-scripts/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "0.2.2",
+ "changes": [
+ {
+ "note": "Fix git remote tag removal step & add an additional sanity assertion",
+ "pr": 803
+ }
+ ]
+ },
+ {
"timestamp": 1529397769,
"version": "0.2.1",
"changes": [
diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts
index 1c4ee1fc6..3b4ff9082 100644
--- a/packages/monorepo-scripts/src/prepublish_checks.ts
+++ b/packages/monorepo-scripts/src/prepublish_checks.ts
@@ -34,17 +34,17 @@ async function checkGitTagsForNextVersionAndDeleteIfExistAsync(
const packageLocation = lernaPackage.location;
const nextVersion = await utils.getNextPackageVersionAsync(currentVersion, packageName, packageLocation);
- const localTagVersions = localTagVersionsByPackageName[packageName];
- if (_.includes(localTagVersions, nextVersion)) {
- const tagName = `${packageName}@${nextVersion}`;
- await utils.removeLocalTagAsync(tagName);
- }
-
const remoteTagVersions = remoteTagVersionsByPackageName[packageName];
if (_.includes(remoteTagVersions, nextVersion)) {
const tagName = `:refs/tags/${packageName}@${nextVersion}`;
await utils.removeRemoteTagAsync(tagName);
}
+
+ const localTagVersions = localTagVersionsByPackageName[packageName];
+ if (_.includes(localTagVersions, nextVersion)) {
+ const tagName = `${packageName}@${nextVersion}`;
+ await utils.removeLocalTagAsync(tagName);
+ }
}
}
diff --git a/packages/monorepo-scripts/src/utils/utils.ts b/packages/monorepo-scripts/src/utils/utils.ts
index 20bc57bae..f819ab6f1 100644
--- a/packages/monorepo-scripts/src/utils/utils.ts
+++ b/packages/monorepo-scripts/src/utils/utils.ts
@@ -44,6 +44,9 @@ export const utils = {
nextVersionIfValid = semver.inc(currentVersion, 'patch');
}
const lastEntry = changelog[0];
+ if (semver.gt(currentVersion, lastEntry.version)) {
+ throw new Error(`Package.json version cannot be greater then last CHANGELOG entry. Check: ${packageName}`);
+ }
nextVersionIfValid = semver.eq(lastEntry.version, currentVersion)
? semver.inc(currentVersion, 'patch')
: lastEntry.version;
@@ -100,19 +103,23 @@ export const utils = {
return tagVersionByPackageName;
},
async removeLocalTagAsync(tagName: string): Promise<void> {
- const result = await execAsync(`git tag -d ${tagName}`, {
- cwd: constants.monorepoRootPath,
- });
- if (!_.isEmpty(result.stderr)) {
- throw new Error(`Failed to delete local git tag. Got err: ${result.stderr}`);
+ try {
+ await execAsync(`git tag -d ${tagName}`, {
+ cwd: constants.monorepoRootPath,
+ });
+ } catch (err) {
+ throw new Error(`Failed to delete local git tag. Got err: ${err}`);
}
+ this.log(`Removed local tag: ${tagName}`);
},
async removeRemoteTagAsync(tagName: string): Promise<void> {
- const result = await execAsync(`git push origin ${tagName}`, {
- cwd: constants.monorepoRootPath,
- });
- if (!_.isEmpty(result.stderr)) {
- throw new Error(`Failed to delete remote git tag. Got err: ${result.stderr}`);
+ try {
+ await execAsync(`git push origin ${tagName}`, {
+ cwd: constants.monorepoRootPath,
+ });
+ } catch (err) {
+ throw new Error(`Failed to delete remote git tag. Got err: ${err}`);
}
+ this.log(`Removed remote tag: ${tagName}`);
},
};
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json
index a1f199793..199ce2173 100644
--- a/packages/order-utils/CHANGELOG.json
+++ b/packages/order-utils/CHANGELOG.json
@@ -1,8 +1,12 @@
[
{
- "version": "0.1.0",
+ "version": "1.0.0",
"changes": [
{
+ "note": "Refactor to work with V2 of 0x protocol",
+ "pr": 636
+ },
+ {
"note": "Export parseECSignature method",
"pr": 684
}
diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json
index e3c81de44..97b08c3d3 100644
--- a/packages/order-utils/package.json
+++ b/packages/order-utils/package.json
@@ -82,7 +82,7 @@
"@0xproject/web3-wrapper": "^0.7.1",
"@types/node": "^8.0.53",
"bn.js": "^4.11.8",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts
index 54428f77d..94df3ef82 100644
--- a/packages/order-utils/src/order_validation_utils.ts
+++ b/packages/order-utils/src/order_validation_utils.ts
@@ -140,12 +140,12 @@ export class OrderValidationUtils {
takerAddress: string,
zrxAssetData: string,
): Promise<BigNumber> {
- if (fillTakerAssetAmount.eq(0)) {
- throw new Error(RevertReason.InvalidTakerAmount);
- }
if (signedOrder.makerAssetAmount.eq(0) || signedOrder.takerAssetAmount.eq(0)) {
throw new Error(RevertReason.OrderUnfillable);
}
+ if (fillTakerAssetAmount.eq(0)) {
+ throw new Error(RevertReason.InvalidTakerAmount);
+ }
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const isValid = await isValidSignatureAsync(
provider,
diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json
index 3335713a3..40613ea96 100644
--- a/packages/order-watcher/package.json
+++ b/packages/order-watcher/package.json
@@ -85,9 +85,9 @@
"@0xproject/order-utils": "^0.0.7",
"@0xproject/types": "^0.8.1",
"@0xproject/typescript-typings": "^0.4.1",
- "@0xproject/utils": "^0.7.3",
+ "@0xproject/utils": "^0.7.2",
"@0xproject/web3-wrapper": "^0.7.1",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"bintrees": "^1.0.2",
"ethers": "3.0.22",
"lodash": "^4.17.4"
diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts
index 140aa341b..0ee56592e 100644
--- a/packages/order-watcher/src/order_watcher/order_watcher.ts
+++ b/packages/order-watcher/src/order_watcher/order_watcher.ts
@@ -1,7 +1,10 @@
import {
BalanceAndProxyAllowanceLazyStore,
ContractWrappers,
+ LogCancelContractEventArgs,
+ LogFillContractEventArgs,
OrderFilledCancelledLazyStore,
+ WithdrawalContractEventArgs,
} from '@0xproject/contract-wrappers';
import { schemas } from '@0xproject/json-schemas';
import { getOrderHashHex, OrderStateUtils } from '@0xproject/order-utils';
@@ -23,14 +26,8 @@ import {
DepositContractEventArgs,
EtherTokenContractEventArgs,
EtherTokenEvents,
- WithdrawalContractEventArgs,
} from '../generated_contract_wrappers/ether_token';
-import {
- ExchangeContractEventArgs,
- ExchangeEvents,
- LogCancelContractEventArgs,
- LogFillContractEventArgs,
-} from '../generated_contract_wrappers/exchange';
+import { ExchangeContractEventArgs, ExchangeEvents } from '../generated_contract_wrappers/exchange';
import {
ApprovalContractEventArgs,
TokenContractEventArgs,
@@ -301,6 +298,7 @@ export class OrderWatcher {
}
case EtherTokenEvents.Withdrawal: {
// Invalidate cache
+ // tslint:disable-next-line:no-unnecessary-type-assertion
const args = decodedLog.args as WithdrawalContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
// Revalidate orders
@@ -317,6 +315,7 @@ export class OrderWatcher {
}
case ExchangeEvents.LogFill: {
// Invalidate cache
+ // tslint:disable-next-line:no-unnecessary-type-assertion
const args = decodedLog.args as LogFillContractEventArgs;
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
// Revalidate orders
@@ -329,6 +328,7 @@ export class OrderWatcher {
}
case ExchangeEvents.LogCancel: {
// Invalidate cache
+ // tslint:disable-next-line:no-unnecessary-type-assertion
const args = decodedLog.args as LogCancelContractEventArgs;
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
// Revalidate orders
diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json
index 98568c270..d5a2e6e77 100644
--- a/packages/sol-compiler/package.json
+++ b/packages/sol-compiler/package.json
@@ -84,7 +84,7 @@
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
"@types/yargs": "^11.0.0",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"chalk": "^2.3.0",
"ethereumjs-util": "^5.1.1",
"isomorphic-fetch": "^2.2.1",
@@ -93,7 +93,6 @@
"require-from-string": "^2.0.1",
"semver": "^5.5.0",
"solc": "^0.4.23",
- "web3": "^0.20.0",
"web3-eth-abi": "^1.0.0-beta.24",
"yargs": "^10.0.3"
},
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index 3d1b7f900..483500ca9 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -56,7 +56,7 @@
"@0xproject/utils": "^0.7.1",
"@0xproject/web3-wrapper": "^0.7.1",
"@0xproject/dev-utils": "^0.4.4",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"ethereumjs-util": "^5.1.1",
"glob": "^7.1.2",
"istanbul": "^0.4.5",
diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json
index 65a74f7a8..c4dca2864 100644
--- a/packages/subproviders/CHANGELOG.json
+++ b/packages/subproviders/CHANGELOG.json
@@ -1,5 +1,13 @@
[
{
+ "version": "0.11.0",
+ "changes": [
+ {
+ "note": "Add `EthLightwalletSubprovider`"
+ }
+ ]
+ },
+ {
"timestamp": 1529397769,
"version": "0.10.4",
"changes": [
diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json
index 31b6ffed6..8eca91dc7 100644
--- a/packages/subproviders/package.json
+++ b/packages/subproviders/package.json
@@ -41,27 +41,27 @@
},
"dependencies": {
"@0xproject/assert": "^0.2.12",
- "@0xproject/types": "^0.8.1",
- "@0xproject/typescript-typings": "^0.4.1",
+ "@0xproject/types": "^1.0.0",
+ "@0xproject/web3-wrapper": "^0.7.1",
+ "@0xproject/typescript-typings": "^0.4.2",
"@0xproject/utils": "^0.7.1",
"@ledgerhq/hw-app-eth": "^4.3.0",
"@ledgerhq/hw-transport-u2f": "^4.3.0",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"bip39": "^2.5.0",
"bn.js": "^4.11.8",
+ "eth-lightwallet": "^3.0.1",
"ethereumjs-tx": "^1.3.5",
"ethereumjs-util": "^5.1.1",
"ganache-core": "0xProject/ganache-core",
"hdkey": "^0.7.1",
"lodash": "^4.17.4",
"semaphore-async-await": "^1.5.1",
- "web3": "^0.20.0",
- "web3-provider-engine": "^14.0.4"
+ "web3-provider-engine": "14.0.6"
},
"devDependencies": {
"@0xproject/monorepo-scripts": "^0.2.1",
"@0xproject/tslint-config": "^0.4.20",
- "@0xproject/typescript-typings": "^0.4.2",
"@0xproject/utils": "^0.7.1",
"@types/bip39": "^2.4.0",
"@types/bn.js": "^4.11.0",
@@ -70,6 +70,7 @@
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/node": "^8.0.53",
+ "@types/sinon": "^2.2.2",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"copyfiles": "^1.2.0",
@@ -79,6 +80,7 @@
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"shx": "^0.2.2",
+ "sinon": "^4.0.0",
"tslint": "5.8.0",
"typedoc": "0xProject/typedoc",
"typescript": "2.7.1",
diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts
index c00dc4099..94e63a32d 100644
--- a/packages/subproviders/src/globals.d.ts
+++ b/packages/subproviders/src/globals.d.ts
@@ -1,8 +1,3 @@
-// tslint:disable:max-classes-per-file
-// tslint:disable:class-name
-// tslint:disable:async-suffix
-// tslint:disable:completed-docs
-
declare module '*.json' {
const json: any;
/* tslint:disable */
diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts
index 9194c1341..71d643f14 100644
--- a/packages/subproviders/src/index.ts
+++ b/packages/subproviders/src/index.ts
@@ -7,7 +7,7 @@ import { LedgerEthereumClient } from './types';
export { prependSubprovider } from './utils/subprovider_utils';
export { EmptyWalletSubprovider } from './subproviders/empty_wallet_subprovider';
export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_subprovider';
-export { InjectedWeb3Subprovider } from './subproviders/injected_web3';
+export { SignerSubprovider } from './subproviders/signer';
export { RedundantSubprovider } from './subproviders/redundant_subprovider';
export { LedgerSubprovider } from './subproviders/ledger';
export { GanacheSubprovider } from './subproviders/ganache';
@@ -15,6 +15,7 @@ export { Subprovider } from './subproviders/subprovider';
export { NonceTrackerSubprovider } from './subproviders/nonce_tracker';
export { PrivateKeyWalletSubprovider } from './subproviders/private_key_wallet';
export { MnemonicWalletSubprovider } from './subproviders/mnemonic_wallet';
+export { EthLightwalletSubprovider } from './subproviders/eth_lightwallet_subprovider';
export {
Callback,
ErrorCallback,
diff --git a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts b/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts
new file mode 100644
index 000000000..a9ebbb790
--- /dev/null
+++ b/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts
@@ -0,0 +1,68 @@
+import * as lightwallet from 'eth-lightwallet';
+
+import { PartialTxParams } from '../types';
+
+import { BaseWalletSubprovider } from './base_wallet_subprovider';
+import { PrivateKeyWalletSubprovider } from './private_key_wallet';
+
+/*
+ * This class implements the web3-provider-engine subprovider interface and forwards
+ * requests involving user accounts and signing operations to eth-lightwallet
+ *
+ * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
+ */
+export class EthLightwalletSubprovider extends BaseWalletSubprovider {
+ private _keystore: lightwallet.keystore;
+ private _pwDerivedKey: Uint8Array;
+ constructor(keystore: lightwallet.keystore, pwDerivedKey: Uint8Array) {
+ super();
+ this._keystore = keystore;
+ this._pwDerivedKey = pwDerivedKey;
+ }
+ /**
+ * Retrieve the accounts associated with the eth-lightwallet instance.
+ * This method is implicitly called when issuing a `eth_accounts` JSON RPC request
+ * via your providerEngine instance.
+ *
+ * @return An array of accounts
+ */
+ public async getAccountsAsync(): Promise<string[]> {
+ const accounts = this._keystore.getAddresses();
+ return accounts;
+ }
+ /**
+ * Signs a transaction with the account specificed by the `from` field in txParams.
+ * If you've added this Subprovider to your app's provider, you can simply send
+ * an `eth_sendTransaction` JSON RPC request, and this method will be called auto-magically.
+ * If you are not using this via a ProviderEngine instance, you can call it directly.
+ * @param txParams Parameters of the transaction to sign
+ * @return Signed transaction hex string
+ */
+ public async signTransactionAsync(txParams: PartialTxParams): Promise<string> {
+ // Lightwallet loses the chain id information when hex encoding the transaction
+ // this results in a different signature on certain networks. PrivateKeyWallet
+ // respects this as it uses the parameters passed in
+ let privKey = this._keystore.exportPrivateKey(txParams.from, this._pwDerivedKey);
+ const privKeyWallet = new PrivateKeyWalletSubprovider(privKey);
+ privKey = '';
+ const privKeySignature = await privKeyWallet.signTransactionAsync(txParams);
+ return privKeySignature;
+ }
+ /**
+ * Sign a personal Ethereum signed message. The signing account will be the account
+ * associated with the provided address.
+ * If you've added the MnemonicWalletSubprovider to your app's provider, you can simply send an `eth_sign`
+ * or `personal_sign` JSON RPC request, and this method will be called auto-magically.
+ * If you are not using this via a ProviderEngine instance, you can call it directly.
+ * @param data Hex string message to sign
+ * @param address Address of the account to sign with
+ * @return Signature hex string (order: rsv)
+ */
+ public async signPersonalMessageAsync(data: string, address: string): Promise<string> {
+ let privKey = this._keystore.exportPrivateKey(address, this._pwDerivedKey);
+ const privKeyWallet = new PrivateKeyWalletSubprovider(privKey);
+ privKey = '';
+ const result = privKeyWallet.signPersonalMessageAsync(data, address);
+ return result;
+ }
+}
diff --git a/packages/subproviders/src/subproviders/injected_web3.ts b/packages/subproviders/src/subproviders/signer.ts
index 2691dec53..08a9daceb 100644
--- a/packages/subproviders/src/subproviders/injected_web3.ts
+++ b/packages/subproviders/src/subproviders/signer.ts
@@ -1,5 +1,5 @@
+import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { JSONRPCRequestPayload, Provider } from 'ethereum-types';
-import * as Web3 from 'web3';
import { Callback, ErrorCallback } from '../types';
@@ -7,19 +7,19 @@ import { Subprovider } from './subprovider';
/**
* This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine)
- * subprovider interface. It forwards JSON RPC requests involving user accounts (getAccounts,
- * sendTransaction, etc...) to the provider instance supplied at instantiation. All other requests
+ * subprovider interface. It forwards JSON RPC requests involving the domain of a signer (getAccounts,
+ * sendTransaction, signMessage etc...) to the provider instance supplied at instantiation. All other requests
* are passed onwards for subsequent subproviders to handle.
*/
-export class InjectedWeb3Subprovider extends Subprovider {
- private _injectedWeb3: Web3;
+export class SignerSubprovider extends Subprovider {
+ private _web3Wrapper: Web3Wrapper;
/**
- * Instantiates a new InjectedWeb3Subprovider
+ * Instantiates a new SignerSubprovider
* @param provider Web3 provider that should handle all user account related requests
*/
constructor(provider: Provider) {
super();
- this._injectedWeb3 = new Web3(provider);
+ this._web3Wrapper = new Web3Wrapper(provider);
}
/**
* This method conforms to the web3-provider-engine interface.
@@ -33,22 +33,39 @@ export class InjectedWeb3Subprovider extends Subprovider {
public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> {
switch (payload.method) {
case 'web3_clientVersion':
- this._injectedWeb3.version.getNode(end);
+ try {
+ const nodeVersion = await this._web3Wrapper.getNodeVersionAsync();
+ end(null, nodeVersion);
+ } catch (err) {
+ end(err);
+ }
return;
case 'eth_accounts':
- this._injectedWeb3.eth.getAccounts(end);
+ try {
+ const accounts = await this._web3Wrapper.getAvailableAddressesAsync();
+ end(null, accounts);
+ } catch (err) {
+ end(err);
+ }
return;
-
case 'eth_sendTransaction':
const [txParams] = payload.params;
- this._injectedWeb3.eth.sendTransaction(txParams, end);
+ try {
+ const txHash = await this._web3Wrapper.sendTransactionAsync(txParams);
+ end(null, txHash);
+ } catch (err) {
+ end(err);
+ }
return;
-
case 'eth_sign':
const [address, message] = payload.params;
- this._injectedWeb3.eth.sign(address, message, end);
+ try {
+ const signature = await this._web3Wrapper.signMessageAsync(address, message);
+ end(null, signature);
+ } catch (err) {
+ end(err);
+ }
return;
-
default:
next();
return;
diff --git a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts
new file mode 100644
index 000000000..f17c21f02
--- /dev/null
+++ b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts
@@ -0,0 +1,167 @@
+import * as chai from 'chai';
+import * as lightwallet from 'eth-lightwallet';
+import { JSONRPCResponsePayload } from 'ethereum-types';
+import * as ethUtils from 'ethereumjs-util';
+import Web3ProviderEngine = require('web3-provider-engine');
+
+import { EthLightwalletSubprovider } from '../../src';
+import { DoneCallback } from '../../src/types';
+import { chaiSetup } from '../chai_setup';
+import { fixtureData } from '../utils/fixture_data';
+import { ganacheSubprovider } from '../utils/ganache_subprovider';
+import { reportCallbackErrors } from '../utils/report_callback_errors';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+const DEFAULT_NUM_ACCOUNTS = 10;
+const PASSWORD = 'supersecretpassword99';
+const SALT = 'kvODghzs7Ff1uqHyI0P3wI4Hso4w4iWT2e9qmrWz0y4';
+
+describe('EthLightwalletSubprovider', () => {
+ let ethLightwalletSubprovider: EthLightwalletSubprovider;
+ before(async () => {
+ const options = {
+ password: PASSWORD,
+ seedPhrase: fixtureData.TEST_RPC_MNEMONIC,
+ salt: SALT,
+ hdPathString: fixtureData.TESTRPC_BASE_DERIVATION_PATH,
+ };
+ const createVaultAsync = async (vaultOptions: lightwallet.VaultOptions) => {
+ return new Promise<lightwallet.keystore>(resolve => {
+ lightwallet.keystore.createVault(vaultOptions, (err: Error, vaultKeystore) => {
+ if (err) {
+ throw new Error(`Failed to createVault: ${err}`);
+ }
+ resolve(vaultKeystore);
+ });
+ });
+ };
+ const deriveKeyFromPasswordAsync = async (vaultKeystore: lightwallet.keystore) => {
+ return new Promise<Uint8Array>(resolve => {
+ vaultKeystore.keyFromPassword(PASSWORD, (err: Error, passwordDerivedKey: Uint8Array) => {
+ if (err) {
+ throw new Error(`Failed to get key from password: ${err}`);
+ }
+ resolve(passwordDerivedKey);
+ });
+ });
+ };
+ const keystore: lightwallet.keystore = await createVaultAsync(options);
+ const pwDerivedKey: Uint8Array = await deriveKeyFromPasswordAsync(keystore);
+
+ // Generate 10 addresses
+ keystore.generateNewAddress(pwDerivedKey, DEFAULT_NUM_ACCOUNTS);
+
+ ethLightwalletSubprovider = new EthLightwalletSubprovider(keystore, pwDerivedKey);
+ });
+ describe('direct method calls', () => {
+ describe('success cases', () => {
+ it('returns a list of accounts', async () => {
+ const accounts = await ethLightwalletSubprovider.getAccountsAsync();
+ expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
+ expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1);
+ expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
+ });
+ it('signs a personal message hash', async () => {
+ const accounts = await ethLightwalletSubprovider.getAccountsAsync();
+ const signingAccount = accounts[0];
+ const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
+ const ecSignatureHex = await ethLightwalletSubprovider.signPersonalMessageAsync(data, signingAccount);
+ expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT);
+ });
+ it('signs a transaction', async () => {
+ const txHex = await ethLightwalletSubprovider.signTransactionAsync(fixtureData.TX_DATA);
+ expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT);
+ });
+ });
+ });
+ describe('calls through a provider', () => {
+ let provider: Web3ProviderEngine;
+ before(() => {
+ provider = new Web3ProviderEngine();
+ provider.addProvider(ethLightwalletSubprovider);
+ provider.addProvider(ganacheSubprovider);
+ provider.start();
+ });
+ describe('success cases', () => {
+ it('returns a list of accounts', (done: DoneCallback) => {
+ const payload = {
+ jsonrpc: '2.0',
+ method: 'eth_accounts',
+ params: [],
+ id: 1,
+ };
+ const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
+ expect(err).to.be.a('null');
+ expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
+ expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
+ done();
+ });
+ provider.sendAsync(payload, callback);
+ });
+ it('signs a personal message hash with eth_sign', (done: DoneCallback) => {
+ const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
+ const account = fixtureData.TEST_RPC_ACCOUNT_0;
+ const payload = {
+ jsonrpc: '2.0',
+ method: 'eth_sign',
+ params: [account, data],
+ id: 1,
+ };
+ const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
+ expect(err).to.be.a('null');
+ expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT);
+ done();
+ });
+ provider.sendAsync(payload, callback);
+ });
+ it('signs a transaction', (done: DoneCallback) => {
+ const payload = {
+ jsonrpc: '2.0',
+ method: 'eth_signTransaction',
+ params: [fixtureData.TX_DATA],
+ id: 1,
+ };
+ const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
+ expect(err).to.be.a('null');
+ expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT);
+ done();
+ });
+ provider.sendAsync(payload, callback);
+ });
+ });
+ describe('failure cases', () => {
+ it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => {
+ const nonHexMessage = 'hello world';
+ const payload = {
+ jsonrpc: '2.0',
+ method: 'eth_sign',
+ params: [fixtureData.TEST_RPC_ACCOUNT_0, nonHexMessage],
+ id: 1,
+ };
+ const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => {
+ expect(err).to.not.be.a('null');
+ expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world');
+ done();
+ });
+ provider.sendAsync(payload, callback);
+ });
+ it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => {
+ const nonHexMessage = 'hello world';
+ const payload = {
+ jsonrpc: '2.0',
+ method: 'personal_sign',
+ params: [nonHexMessage, fixtureData.TEST_RPC_ACCOUNT_0],
+ id: 1,
+ };
+ const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => {
+ expect(err).to.not.be.a('null');
+ expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world');
+ done();
+ });
+ provider.sendAsync(payload, callback);
+ });
+ });
+ });
+});
diff --git a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts
index a41ad7790..ab321bcff 100644
--- a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts
+++ b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts
@@ -60,6 +60,20 @@ describe('PrivateKeyWalletSubprovider', () => {
});
provider.sendAsync(payload, callback);
});
+ it('signs a transaction', (done: DoneCallback) => {
+ const payload = {
+ jsonrpc: '2.0',
+ method: 'eth_signTransaction',
+ params: [fixtureData.TX_DATA],
+ id: 1,
+ };
+ const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
+ expect(err).to.be.a('null');
+ expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT);
+ done();
+ });
+ provider.sendAsync(payload, callback);
+ });
it('signs a personal message with eth_sign', (done: DoneCallback) => {
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const payload = {
diff --git a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts
index 593027849..810fb8f45 100644
--- a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts
+++ b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts
@@ -1,6 +1,7 @@
import { DoneCallback } from '@0xproject/types';
import * as chai from 'chai';
import { JSONRPCResponsePayload } from 'ethereum-types';
+import * as Sinon from 'sinon';
import Web3ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
@@ -41,6 +42,9 @@ describe('RedundantSubprovider', () => {
const nonExistentSubprovider = new RpcSubprovider({
rpcUrl: 'http://does-not-exist:3000',
});
+ const handleRequestStub = Sinon.stub(nonExistentSubprovider, 'handleRequest').throws(
+ new Error('REQUEST_FAILED'),
+ );
const subproviders = [nonExistentSubprovider as Subprovider, ganacheSubprovider];
const redundantSubprovider = new RedundantSubprovider(subproviders);
provider.addProvider(redundantSubprovider);
@@ -55,6 +59,7 @@ describe('RedundantSubprovider', () => {
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
+ handleRequestStub.restore();
done();
});
provider.sendAsync(payload, callback);
diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json
index 712ac6795..5acd4ae35 100644
--- a/packages/testnet-faucets/package.json
+++ b/packages/testnet-faucets/package.json
@@ -20,6 +20,7 @@
"dependencies": {
"0x.js": "^0.38.0",
"@0xproject/subproviders": "^0.10.4",
+ "@0xproject/web3-wrapper": "^0.7.1",
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
"body-parser": "^1.17.1",
@@ -28,15 +29,14 @@
"express": "^4.15.2",
"lodash": "^4.17.4",
"rollbar": "^0.6.5",
- "web3": "^0.20.0",
- "web3-provider-engine": "^14.0.4"
+ "web3-provider-engine": "14.0.6"
},
"devDependencies": {
"@0xproject/tslint-config": "^0.4.20",
"@types/body-parser": "^1.16.1",
"@types/express": "^4.0.35",
"@types/lodash": "4.14.104",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"awesome-typescript-loader": "^3.1.3",
"gulp": "^3.9.1",
"make-promises-safe": "^1.1.0",
diff --git a/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts b/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts
index 41b6c90cd..3af5ca747 100644
--- a/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts
+++ b/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts
@@ -1,7 +1,7 @@
import { ZeroEx } from '0x.js';
-import { BigNumber, logUtils, promisify } from '@0xproject/utils';
+import { BigNumber, logUtils } from '@0xproject/utils';
+import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
-import * as Web3 from 'web3';
import { configs } from './configs';
@@ -13,22 +13,21 @@ const DISPENSE_MAX_AMOUNT_ETHER = 2;
type AsyncTask = () => Promise<void>;
export const dispenseAssetTasks = {
- dispenseEtherTask(recipientAddress: string, web3: Web3): AsyncTask {
+ dispenseEtherTask(recipientAddress: string, web3Wrapper: Web3Wrapper): AsyncTask {
return async () => {
logUtils.log(`Processing ETH ${recipientAddress}`);
- const userBalance = await promisify<BigNumber>(web3.eth.getBalance)(recipientAddress);
- const maxAmountInWei = new BigNumber(web3.toWei(DISPENSE_MAX_AMOUNT_ETHER, 'ether'));
+ const userBalance = await web3Wrapper.getBalanceInWeiAsync(recipientAddress);
+ const maxAmountInWei = Web3Wrapper.toWei(new BigNumber(DISPENSE_MAX_AMOUNT_ETHER));
if (userBalance.greaterThanOrEqualTo(maxAmountInWei)) {
logUtils.log(
`User exceeded ETH balance maximum (${maxAmountInWei}) ${recipientAddress} ${userBalance} `,
);
return;
}
- const sendTransactionAsync = promisify(web3.eth.sendTransaction);
- const txHash = await sendTransactionAsync({
+ const txHash = await web3Wrapper.sendTransactionAsync({
from: configs.DISPENSER_ADDRESS,
to: recipientAddress,
- value: web3.toWei(DISPENSE_AMOUNT_ETHER, 'ether'),
+ value: Web3Wrapper.toWei(new BigNumber(DISPENSE_AMOUNT_ETHER)),
});
logUtils.log(`Sent ${DISPENSE_AMOUNT_ETHER} ETH to ${recipientAddress} tx: ${txHash}`);
};
diff --git a/packages/testnet-faucets/src/ts/handler.ts b/packages/testnet-faucets/src/ts/handler.ts
index 3a60d396c..6d26691d6 100644
--- a/packages/testnet-faucets/src/ts/handler.ts
+++ b/packages/testnet-faucets/src/ts/handler.ts
@@ -1,15 +1,10 @@
import { Order, ZeroEx } from '0x.js';
import { BigNumber, logUtils } from '@0xproject/utils';
+import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as express from 'express';
import * as _ from 'lodash';
-import * as Web3 from 'web3';
-// HACK: web3 injects XMLHttpRequest into the global scope and ProviderEngine checks XMLHttpRequest
-// to know whether it is running in a browser or node environment. We need it to be undefined since
-// we are not running in a browser env.
-// Filed issue: https://github.com/ethereum/web3.js/issues/844
-(global as any).XMLHttpRequest = undefined;
import { NonceTrackerSubprovider, PrivateKeyWalletSubprovider } from '@0xproject/subproviders';
import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
@@ -22,7 +17,7 @@ import { rpcUrls } from './rpc_urls';
interface NetworkConfig {
dispatchQueue: DispatchQueue;
- web3: Web3;
+ web3Wrapper: Web3Wrapper;
zeroEx: ZeroEx;
}
@@ -58,15 +53,15 @@ export class Handler {
constructor() {
_.forIn(rpcUrls, (rpcUrl: string, networkId: string) => {
const providerObj = Handler._createProviderEngine(rpcUrl);
- const web3 = new Web3(providerObj);
+ const web3Wrapper = new Web3Wrapper(providerObj);
const zeroExConfig = {
networkId: +networkId,
};
- const zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
+ const zeroEx = new ZeroEx(providerObj, zeroExConfig);
const dispatchQueue = new DispatchQueue();
this._networkConfigByNetworkId[networkId] = {
dispatchQueue,
- web3,
+ web3Wrapper,
zeroEx,
};
});
@@ -106,7 +101,7 @@ export class Handler {
let dispenserTask;
switch (requestedAssetType) {
case RequestedAssetType.ETH:
- dispenserTask = dispenseAssetTasks.dispenseEtherTask(recipient, networkConfig.web3);
+ dispenserTask = dispenseAssetTasks.dispenseEtherTask(recipient, networkConfig.web3Wrapper);
break;
case RequestedAssetType.WETH:
case RequestedAssetType.ZRX:
diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json
index 40197ab92..46e67c970 100644
--- a/packages/types/CHANGELOG.json
+++ b/packages/types/CHANGELOG.json
@@ -1,5 +1,16 @@
[
{
+ "version": "1.0.0",
+ "changes": [
+ {
+ "notes": "Updated types for V2 of 0x protocol"
+ },
+ {
+ "note": "Add `ECSignatureBuffer`"
+ }
+ ]
+ },
+ {
"timestamp": 1529397769,
"version": "0.8.1",
"changes": [
diff --git a/packages/types/package.json b/packages/types/package.json
index 0d5e308b9..f79b558fa 100644
--- a/packages/types/package.json
+++ b/packages/types/package.json
@@ -35,7 +35,7 @@
"dependencies": {
"@types/node": "^8.0.53",
"bignumber.js": "~4.1.0",
- "ethereum-types": "^0.0.1"
+ "ethereum-types": "^0.0.2"
},
"publishConfig": {
"access": "public"
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index 4ad10fdee..9514320da 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -48,6 +48,12 @@ export interface ECSignature {
s: string;
}
+export interface ECSignatureBuffer {
+ v: number;
+ r: Buffer;
+ s: Buffer;
+}
+
/**
* Validator signature components
*/
diff --git a/packages/typescript-typings/CHANGELOG.json b/packages/typescript-typings/CHANGELOG.json
index 1f397e622..1d4230783 100644
--- a/packages/typescript-typings/CHANGELOG.json
+++ b/packages/typescript-typings/CHANGELOG.json
@@ -3,6 +3,10 @@
"version": "0.4.2",
"changes": [
{
+ "note": "Add types for `eth-lightwallet`",
+ "pr": 775
+ },
+ {
"note": "Improve 'web3-provider-engine' typings",
"pr": 768
},
diff --git a/packages/typescript-typings/package.json b/packages/typescript-typings/package.json
index 3ba7c10ba..e3f226294 100644
--- a/packages/typescript-typings/package.json
+++ b/packages/typescript-typings/package.json
@@ -25,7 +25,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/typescript-typings#readme",
"dependencies": {
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"bignumber.js": "~4.1.0"
},
"devDependencies": {
diff --git a/packages/typescript-typings/types/eth-lightwallet/index.d.ts b/packages/typescript-typings/types/eth-lightwallet/index.d.ts
new file mode 100644
index 000000000..58096e9f4
--- /dev/null
+++ b/packages/typescript-typings/types/eth-lightwallet/index.d.ts
@@ -0,0 +1,50 @@
+// eth-lightwallet declarations
+declare module 'eth-lightwallet' {
+ import { ECSignatureBuffer } from '@0xproject/types';
+
+ // tslint:disable-next-line:class-name
+ export class signing {
+ public static signTx(
+ keystore: keystore,
+ pwDerivedKey: Uint8Array,
+ rawTx: string,
+ signingAddress: string,
+ ): string;
+ public static signMsg(
+ keystore: keystore,
+ pwDerivedKey: Uint8Array,
+ rawMsg: string,
+ signingAddress: string,
+ ): ECSignatureBuffer;
+ public static signMsgHash(
+ keystore: keystore,
+ pwDerivedKey: Uint8Array,
+ msgHash: string,
+ signingAddress: string,
+ ): ECSignatureBuffer;
+ public static concatSig(signature: any): string;
+ }
+ // tslint:disable-next-line:class-name
+ export class keystore {
+ public static createVault(options: any, callback?: (error: Error, keystore: keystore) => void): keystore;
+ public static generateRandomSeed(): string;
+ public static isSeedValid(seed: string): boolean;
+ public static deserialize(keystore: string): keystore;
+ public serialize(): string;
+ public keyFromPassword(
+ password: string,
+ callback?: (error: Error, pwDerivedKey: Uint8Array) => void,
+ ): Uint8Array;
+ public isDerivedKeyCorrect(pwDerivedKey: Uint8Array): boolean;
+ public generateNewAddress(pwDerivedKey: Uint8Array, numberOfAddresses: number): void;
+ public getSeed(pwDerivedKey: Uint8Array): string;
+ public exportPrivateKey(address: string, pwDerivedKey: Uint8Array): string;
+ public getAddresses(): string[];
+ }
+ interface VaultOptions {
+ password: string;
+ seedPhrase: string;
+ salt?: string;
+ hdPathString: string;
+ }
+}
diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index c6736dc4d..a27216be7 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -1,14 +1,5 @@
[
{
- "version": "0.7.3",
- "changes": [
- {
- "note": "Fixes uncaught Error in abi_decoder",
- "pr": 763
- }
- ]
- },
- {
"version": "0.7.2",
"changes": [
{
@@ -17,6 +8,10 @@
{
"note": "Add logUtils.warn",
"pr": 589
+ },
+ {
+ "note": "Fixes uncaught Error in abi_decoder",
+ "pr": 763
}
]
},
diff --git a/packages/utils/package.json b/packages/utils/package.json
index f4f39956c..0ba7a7ba4 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0xproject/utils",
- "version": "0.7.3",
+ "version": "0.7.2",
"engines": {
"node": ">=6.12"
},
@@ -35,15 +35,14 @@
"typescript": "2.7.1"
},
"dependencies": {
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
"@0xproject/typescript-typings": "^0.4.2",
"@types/node": "^8.0.53",
"ethereumjs-util": "^5.1.1",
"bignumber.js": "~4.1.0",
"ethers": "3.0.22",
"js-sha3": "^0.7.0",
- "lodash": "^4.17.4",
- "web3": "^0.20.0"
+ "lodash": "^4.17.4"
},
"publishConfig": {
"access": "public"
diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json
index 624ad7151..f8b1dab85 100644
--- a/packages/web3-wrapper/CHANGELOG.json
+++ b/packages/web3-wrapper/CHANGELOG.json
@@ -1,6 +1,16 @@
[
{
"timestamp": 1529397769,
+ "version": "0.7.2",
+ "changes": [
+ {
+ "note": "Add `getNodeTypeAsync` method",
+ "pr": 812
+ }
+ ]
+ },
+ {
+ "timestamp": 1529397769,
"version": "0.7.1",
"changes": [
{
diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json
index 5f7f2cb00..ccd41fa1d 100644
--- a/packages/web3-wrapper/package.json
+++ b/packages/web3-wrapper/package.json
@@ -64,12 +64,14 @@
"typescript": "2.7.1"
},
"dependencies": {
+ "@0xproject/assert": "^0.2.12",
+ "@0xproject/json-schemas": "^1.0.0",
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
- "ethereum-types": "^0.0.1",
+ "ethereum-types": "^0.0.2",
+ "ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
- "lodash": "^4.17.4",
- "web3": "^0.20.0"
+ "lodash": "^4.17.4"
},
"publishConfig": {
"access": "public"
diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts
index b14fa7406..66ef0a784 100644
--- a/packages/web3-wrapper/src/index.ts
+++ b/packages/web3-wrapper/src/index.ts
@@ -1,2 +1,2 @@
-export { Web3Wrapper, uniqueVersionIds } from './web3_wrapper';
+export { Web3Wrapper, uniqueVersionIds, NodeType } from './web3_wrapper';
export { Web3WrapperErrors } from './types';
diff --git a/packages/web3-wrapper/src/marshaller.ts b/packages/web3-wrapper/src/marshaller.ts
new file mode 100644
index 000000000..e9fd35a11
--- /dev/null
+++ b/packages/web3-wrapper/src/marshaller.ts
@@ -0,0 +1,149 @@
+import { addressUtils } from '@0xproject/utils';
+import {
+ BlockParam,
+ BlockParamLiteral,
+ BlockWithoutTransactionData,
+ BlockWithTransactionData,
+ CallData,
+ CallTxDataBase,
+ LogEntry,
+ RawLogEntry,
+ Transaction,
+ TxData,
+} from 'ethereum-types';
+import ethUtil = require('ethereumjs-util');
+import * as _ from 'lodash';
+
+import { utils } from './utils';
+
+import {
+ BlockWithoutTransactionDataRPC,
+ BlockWithTransactionDataRPC,
+ CallDataRPC,
+ CallTxDataBaseRPC,
+ TransactionRPC,
+ TxDataRPC,
+} from './types';
+
+export const marshaller = {
+ unmarshalIntoBlockWithoutTransactionData(
+ blockWithHexValues: BlockWithoutTransactionDataRPC,
+ ): BlockWithoutTransactionData {
+ const block = {
+ ...blockWithHexValues,
+ gasLimit: utils.convertHexToNumber(blockWithHexValues.gasLimit),
+ gasUsed: utils.convertHexToNumber(blockWithHexValues.gasUsed),
+ size: utils.convertHexToNumber(blockWithHexValues.size),
+ timestamp: utils.convertHexToNumber(blockWithHexValues.timestamp),
+ number: _.isNull(blockWithHexValues.number) ? null : utils.convertHexToNumber(blockWithHexValues.number),
+ difficulty: utils.convertAmountToBigNumber(blockWithHexValues.difficulty),
+ totalDifficulty: utils.convertAmountToBigNumber(blockWithHexValues.totalDifficulty),
+ };
+ return block;
+ },
+ unmarshalIntoBlockWithTransactionData(blockWithHexValues: BlockWithTransactionDataRPC): BlockWithTransactionData {
+ const block = {
+ ...blockWithHexValues,
+ gasLimit: utils.convertHexToNumber(blockWithHexValues.gasLimit),
+ gasUsed: utils.convertHexToNumber(blockWithHexValues.gasUsed),
+ size: utils.convertHexToNumber(blockWithHexValues.size),
+ timestamp: utils.convertHexToNumber(blockWithHexValues.timestamp),
+ number: _.isNull(blockWithHexValues.number) ? null : utils.convertHexToNumber(blockWithHexValues.number),
+ difficulty: utils.convertAmountToBigNumber(blockWithHexValues.difficulty),
+ totalDifficulty: utils.convertAmountToBigNumber(blockWithHexValues.totalDifficulty),
+ transactions: [] as Transaction[],
+ };
+ block.transactions = _.map(blockWithHexValues.transactions, (tx: TransactionRPC) => {
+ const transaction = this.unmarshalTransaction(tx);
+ return transaction;
+ });
+ return block;
+ },
+ unmarshalTransaction(txRpc: TransactionRPC): Transaction {
+ const tx = {
+ ...txRpc,
+ blockNumber: !_.isNull(txRpc.blockNumber) ? utils.convertHexToNumber(txRpc.blockNumber) : null,
+ transactionIndex: !_.isNull(txRpc.transactionIndex)
+ ? utils.convertHexToNumber(txRpc.transactionIndex)
+ : null,
+ nonce: utils.convertHexToNumber(txRpc.nonce),
+ gas: utils.convertHexToNumber(txRpc.gas),
+ gasPrice: utils.convertAmountToBigNumber(txRpc.gasPrice),
+ value: utils.convertAmountToBigNumber(txRpc.value),
+ };
+ return tx;
+ },
+ marshalTxData(txData: Partial<TxData>): Partial<TxDataRPC> {
+ if (_.isUndefined(txData.from)) {
+ throw new Error(`txData must include valid 'from' value.`);
+ }
+ const callTxDataBase = {
+ ...txData,
+ };
+ delete callTxDataBase.from;
+ const callTxDataBaseRPC = this._marshalCallTxDataBase(callTxDataBase);
+ const txDataRPC = {
+ ...callTxDataBaseRPC,
+ from: this.marshalAddress(txData.from),
+ };
+ const prunableIfUndefined = ['gasPrice', 'gas', 'value', 'nonce'];
+ _.each(txDataRPC, (value: any, key: string) => {
+ if (_.isUndefined(value) && _.includes(prunableIfUndefined, key)) {
+ delete (txDataRPC as any)[key];
+ }
+ });
+ return txDataRPC;
+ },
+ marshalCallData(callData: Partial<CallData>): Partial<CallDataRPC> {
+ const callTxDataBase = {
+ ...callData,
+ };
+ delete callTxDataBase.from;
+ const callTxDataBaseRPC = this._marshalCallTxDataBase(callTxDataBase);
+ const callDataRPC = {
+ ...callTxDataBaseRPC,
+ from: _.isUndefined(callData.from) ? undefined : this.marshalAddress(callData.from),
+ };
+ return callDataRPC;
+ },
+ marshalAddress(address: string): string {
+ if (addressUtils.isAddress(address)) {
+ return ethUtil.addHexPrefix(address);
+ }
+ throw new Error(`Invalid address encountered: ${address}`);
+ },
+ marshalBlockParam(blockParam: BlockParam | string | number | undefined): string | undefined {
+ if (_.isUndefined(blockParam)) {
+ return BlockParamLiteral.Latest;
+ }
+ const encodedBlockParam = _.isNumber(blockParam) ? utils.numberToHex(blockParam) : blockParam;
+ return encodedBlockParam;
+ },
+ unmarshalLog(rawLog: RawLogEntry): LogEntry {
+ const formattedLog = {
+ ...rawLog,
+ logIndex: utils.convertHexToNumberOrNull(rawLog.logIndex),
+ blockNumber: utils.convertHexToNumberOrNull(rawLog.blockNumber),
+ transactionIndex: utils.convertHexToNumberOrNull(rawLog.transactionIndex),
+ };
+ return formattedLog;
+ },
+ _marshalCallTxDataBase(callTxDataBase: Partial<CallTxDataBase>): Partial<CallTxDataBaseRPC> {
+ const callTxDataBaseRPC = {
+ ...callTxDataBase,
+ to: _.isUndefined(callTxDataBase.to) ? undefined : this.marshalAddress(callTxDataBase.to),
+ gasPrice: _.isUndefined(callTxDataBase.gasPrice)
+ ? undefined
+ : utils.encodeAmountAsHexString(callTxDataBase.gasPrice),
+ gas: _.isUndefined(callTxDataBase.gas) ? undefined : utils.encodeAmountAsHexString(callTxDataBase.gas),
+ value: _.isUndefined(callTxDataBase.value)
+ ? undefined
+ : utils.encodeAmountAsHexString(callTxDataBase.value),
+ nonce: _.isUndefined(callTxDataBase.nonce)
+ ? undefined
+ : utils.encodeAmountAsHexString(callTxDataBase.nonce),
+ };
+
+ return callTxDataBaseRPC;
+ },
+};
diff --git a/packages/web3-wrapper/src/types.ts b/packages/web3-wrapper/src/types.ts
index 79542da10..b7b6bd68a 100644
--- a/packages/web3-wrapper/src/types.ts
+++ b/packages/web3-wrapper/src/types.ts
@@ -1,3 +1,59 @@
export enum Web3WrapperErrors {
TransactionMiningTimeout = 'TRANSACTION_MINING_TIMEOUT',
}
+
+export interface AbstractBlockRPC {
+ number: string | null;
+ hash: string | null;
+ parentHash: string;
+ nonce: string | null;
+ sha3Uncles: string;
+ logsBloom: string | null;
+ transactionsRoot: string;
+ stateRoot: string;
+ miner: string;
+ difficulty: string;
+ totalDifficulty: string;
+ extraData: string;
+ size: string;
+ gasLimit: string;
+ gasUsed: string;
+ timestamp: string;
+ uncles: string[];
+}
+export interface BlockWithoutTransactionDataRPC extends AbstractBlockRPC {
+ transactions: string[];
+}
+export interface BlockWithTransactionDataRPC extends AbstractBlockRPC {
+ transactions: TransactionRPC[];
+}
+export interface TransactionRPC {
+ hash: string;
+ nonce: string;
+ blockHash: string | null;
+ blockNumber: string | null;
+ transactionIndex: string | null;
+ from: string;
+ to: string | null;
+ value: string;
+ gasPrice: string;
+ gas: string;
+ input: string;
+}
+
+export interface CallTxDataBaseRPC {
+ to?: string;
+ value?: string;
+ gas?: string;
+ gasPrice?: string;
+ data?: string;
+ nonce?: string;
+}
+
+export interface TxDataRPC extends CallTxDataBaseRPC {
+ from: string;
+}
+
+export interface CallDataRPC extends CallTxDataBaseRPC {
+ from?: string;
+}
diff --git a/packages/web3-wrapper/src/utils.ts b/packages/web3-wrapper/src/utils.ts
new file mode 100644
index 000000000..d13eb9404
--- /dev/null
+++ b/packages/web3-wrapper/src/utils.ts
@@ -0,0 +1,58 @@
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+
+export const utils = {
+ isBigNumber(value: any): boolean {
+ const isBigNumber = _.isObject(value) && value.isBigNumber;
+ return isBigNumber;
+ },
+ convertHexToNumber(value: string): number {
+ const valueBigNumber = new BigNumber(value);
+ const valueNumber = valueBigNumber.toNumber();
+ return valueNumber;
+ },
+ convertHexToNumberOrNull(hex: string | null): number | null {
+ if (_.isNull(hex)) {
+ return null;
+ }
+ const decimal = this.convertHexToNumber(hex);
+ return decimal;
+ },
+ convertAmountToBigNumber(value: string | number | BigNumber): BigNumber {
+ const num = value || 0;
+ const isBigNumber = utils.isBigNumber(num);
+ if (isBigNumber) {
+ return num as BigNumber;
+ }
+
+ if (_.isString(num) && (num.indexOf('0x') === 0 || num.indexOf('-0x') === 0)) {
+ return new BigNumber(num.replace('0x', ''), 16);
+ }
+
+ const baseTen = 10;
+ return new BigNumber((num as number).toString(baseTen), baseTen);
+ },
+ encodeAmountAsHexString(value: string | number | BigNumber): string {
+ const valueBigNumber = utils.convertAmountToBigNumber(value);
+ const hexBase = 16;
+ const valueHex = valueBigNumber.toString(hexBase);
+
+ return valueBigNumber.lessThan(0) ? '-0x' + valueHex.substr(1) : '0x' + valueHex;
+ },
+ numberToHex(value: number): string {
+ if (!isFinite(value) && !this.isHexStrict(value)) {
+ throw new Error(`Given input ${value} is not a number.`);
+ }
+
+ const valueBigNumber = new BigNumber(value);
+ const hexBase = 16;
+ const result = valueBigNumber.toString(hexBase);
+
+ return valueBigNumber.lt(0) ? '-0x' + result.substr(1) : '0x' + result;
+ },
+ isHexStrict(hex: string | number): boolean {
+ return (
+ (_.isString(hex) || _.isNumber(hex)) && /^(-)?0x[0-9a-f]*$/i.test(_.isNumber(hex) ? hex.toString() : hex)
+ );
+ },
+};
diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts
index 6ea69883c..495523e44 100644
--- a/packages/web3-wrapper/src/web3_wrapper.ts
+++ b/packages/web3-wrapper/src/web3_wrapper.ts
@@ -1,10 +1,12 @@
+import { assert } from '@0xproject/assert';
+import { schemas } from '@0xproject/json-schemas';
import { AbiDecoder, addressUtils, BigNumber, intervalUtils, promisify } from '@0xproject/utils';
import {
BlockParam,
+ BlockParamLiteral,
BlockWithoutTransactionData,
BlockWithTransactionData,
CallData,
- ContractAbi,
FilterObject,
JSONRPCRequestPayload,
JSONRPCResponsePayload,
@@ -18,9 +20,10 @@ import {
TxData,
} from 'ethereum-types';
import * as _ from 'lodash';
-import * as Web3 from 'web3';
-import { Web3WrapperErrors } from './types';
+import { marshaller } from './marshaller';
+import { BlockWithoutTransactionDataRPC, BlockWithTransactionDataRPC, Web3WrapperErrors } from './types';
+import { utils } from './utils';
const BASE_TEN = 10;
@@ -31,8 +34,14 @@ export const uniqueVersionIds = {
ganache: 'EthereumJS TestRPC',
};
+// NodeType represents the type of the backing Ethereum node.
+export enum NodeType {
+ Geth = 'GETH',
+ Ganache = 'GANACHE',
+}
+
/**
- * A wrapper around the Web3.js 0.x library that provides a consistent, clean promise-based interface.
+ * An alternative to the Web3.js library that provides a consistent, clean, promise-based interface.
*/
export class Web3Wrapper {
/**
@@ -40,7 +49,7 @@ export class Web3Wrapper {
*/
public isZeroExWeb3Wrapper = true;
public abiDecoder: AbiDecoder;
- private _web3: Web3;
+ private _provider: Provider;
private _txDefaults: Partial<TxData>;
private _jsonRpcRequestId: number;
/**
@@ -60,6 +69,8 @@ export class Web3Wrapper {
* @return The amount in units.
*/
public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
+ assert.isValidBaseUnitAmount('amount', amount);
+ assert.isNumber('decimals', decimals);
const aUnit = new BigNumber(BASE_TEN).pow(decimals);
const unit = amount.div(aUnit);
return unit;
@@ -73,6 +84,8 @@ export class Web3Wrapper {
* @return The amount in baseUnits.
*/
public static toBaseUnitAmount(amount: BigNumber, decimals: number): BigNumber {
+ assert.isBigNumber('amount', amount);
+ assert.isNumber('decimals', decimals);
const unit = new BigNumber(BASE_TEN).pow(decimals);
const baseUnitAmount = amount.times(unit);
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
@@ -87,10 +100,44 @@ export class Web3Wrapper {
* @returns Amount in wei
*/
public static toWei(ethAmount: BigNumber): BigNumber {
+ assert.isBigNumber('ethAmount', ethAmount);
const ETH_DECIMALS = 18;
const balanceWei = Web3Wrapper.toBaseUnitAmount(ethAmount, ETH_DECIMALS);
return balanceWei;
}
+ private static _assertBlockParam(blockParam: string | BlockParam): void {
+ if (_.isNumber(blockParam)) {
+ return;
+ } else if (_.isString(blockParam)) {
+ assert.doesBelongToStringEnum('blockParam', blockParam, BlockParamLiteral);
+ }
+ }
+ private static _assertBlockParamOrString(blockParam: string | BlockParam): void {
+ try {
+ Web3Wrapper._assertBlockParam(blockParam);
+ } catch (err) {
+ try {
+ assert.isHexString('blockParam', blockParam as string);
+ return;
+ } catch (err) {
+ throw new Error(`Expected blockParam to be of type "string | BlockParam", encountered ${blockParam}`);
+ }
+ }
+ }
+ private static _normalizeTxReceiptStatus(status: undefined | null | string | 0 | 1): null | 0 | 1 {
+ // Transaction status might have four values
+ // undefined - Testrpc and other old clients
+ // null - New clients on old transactions
+ // number - Parity
+ // hex - Geth
+ if (_.isString(status)) {
+ return utils.convertHexToNumber(status) as 0 | 1;
+ } else if (_.isUndefined(status)) {
+ return null;
+ } else {
+ return status;
+ }
+ }
/**
* Instantiates a new Web3Wrapper.
* @param provider The Web3 provider instance you would like the Web3Wrapper to use for interacting with
@@ -99,6 +146,7 @@ export class Web3Wrapper {
* @return An instance of the Web3Wrapper class.
*/
constructor(provider: Provider, txDefaults?: Partial<TxData>) {
+ assert.isWeb3Provider('provider', provider);
if (_.isUndefined((provider as any).sendAsync)) {
// Web3@1.0 provider doesn't support synchronous http requests,
// so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x`
@@ -106,8 +154,7 @@ export class Web3Wrapper {
(provider as any).sendAsync = (provider as any).send;
}
this.abiDecoder = new AbiDecoder([]);
- this._web3 = new Web3();
- this._web3.setProvider(provider);
+ this._provider = provider;
this._txDefaults = txDefaults || {};
this._jsonRpcRequestId = 0;
}
@@ -123,14 +170,15 @@ export class Web3Wrapper {
* @return Web3 provider instance
*/
public getProvider(): Provider {
- return this._web3.currentProvider;
+ return this._provider;
}
/**
* Update the used Web3 provider
* @param provider The new Web3 provider to be set
*/
public setProvider(provider: Provider): void {
- this._web3.setProvider(provider);
+ assert.isWeb3Provider('provider', provider);
+ this._provider = provider;
}
/**
* Check whether an address is available through the backing provider. This can be
@@ -140,6 +188,7 @@ export class Web3Wrapper {
* @returns Whether the address is available through the provider.
*/
public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
+ assert.isETHAddressHex('senderAddress', senderAddress);
const addresses = await this.getAvailableAddressesAsync();
const normalizedAddress = senderAddress.toLowerCase();
return _.includes(addresses, normalizedAddress);
@@ -167,9 +216,13 @@ export class Web3Wrapper {
* @returns The transaction receipt, including it's status (0: failed, 1: succeeded or undefined: not found)
*/
public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
- const transactionReceipt = await promisify<TransactionReceipt>(this._web3.eth.getTransactionReceipt)(txHash);
+ assert.isHexString('txHash', txHash);
+ const transactionReceipt = await this._sendRawPayloadAsync<TransactionReceipt>({
+ method: 'eth_getTransactionReceipt',
+ params: [txHash],
+ });
if (!_.isNull(transactionReceipt)) {
- transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status);
+ transactionReceipt.status = Web3Wrapper._normalizeTxReceiptStatus(transactionReceipt.status);
}
return transactionReceipt;
}
@@ -178,11 +231,19 @@ export class Web3Wrapper {
* @param owner Account whose balance you wish to check
* @returns Balance in wei
*/
- public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
- let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
+ public async getBalanceInWeiAsync(owner: string, defaultBlock?: BlockParam): Promise<BigNumber> {
+ assert.isETHAddressHex('owner', owner);
+ if (!_.isUndefined(defaultBlock)) {
+ Web3Wrapper._assertBlockParam(defaultBlock);
+ }
+ const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
+ const encodedOwner = marshaller.marshalAddress(owner);
+ const balanceInWei = await this._sendRawPayloadAsync<string>({
+ method: 'eth_getBalance',
+ params: [encodedOwner, marshalledDefaultBlock],
+ });
// Rewrap in a new BigNumber
- balanceInWei = new BigNumber(balanceInWei);
- return balanceInWei;
+ return new BigNumber(balanceInWei);
}
/**
* Check if a contract exists at a given address
@@ -190,6 +251,7 @@ export class Web3Wrapper {
* @returns Whether or not contract code was found at the supplied address
*/
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
+ assert.isETHAddressHex('address', address);
const code = await this.getContractCodeAsync(address);
// Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients
const isCodeEmpty = /^0x0{0,40}$/i.test(code);
@@ -198,10 +260,20 @@ export class Web3Wrapper {
/**
* Gets the contract code by address
* @param address Address of the contract
+ * @param defaultBlock Block height at which to make the call. Defaults to `latest`
* @return Code of the contract
*/
- public async getContractCodeAsync(address: string): Promise<string> {
- const code = await promisify<string>(this._web3.eth.getCode)(address);
+ public async getContractCodeAsync(address: string, defaultBlock?: BlockParam): Promise<string> {
+ assert.isETHAddressHex('address', address);
+ if (!_.isUndefined(defaultBlock)) {
+ Web3Wrapper._assertBlockParam(defaultBlock);
+ }
+ const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
+ const encodedAddress = marshaller.marshalAddress(address);
+ const code = await this._sendRawPayloadAsync<string>({
+ method: 'eth_getCode',
+ params: [encodedAddress, marshalledDefaultBlock],
+ });
return code;
}
/**
@@ -211,6 +283,7 @@ export class Web3Wrapper {
* @return Transaction trace
*/
public async getTransactionTraceAsync(txHash: string, traceParams: TraceParams): Promise<TransactionTrace> {
+ assert.isHexString('txHash', txHash);
const trace = await this._sendRawPayloadAsync<TransactionTrace>({
method: 'debug_traceTransaction',
params: [txHash, traceParams],
@@ -224,7 +297,13 @@ export class Web3Wrapper {
* @returns Signature string (might be VRS or RSV depending on the Signer)
*/
public async signMessageAsync(address: string, message: string): Promise<string> {
- const signData = await promisify<string>(this._web3.eth.sign)(address, message);
+ assert.isETHAddressHex('address', address);
+ assert.isETHAddressHex('address', address);
+ assert.isString('message', message); // TODO: Should this be stricter? Hex string?
+ const signData = await this._sendRawPayloadAsync<string>({
+ method: 'eth_sign',
+ params: [address, message],
+ });
return signData;
}
/**
@@ -232,8 +311,12 @@ export class Web3Wrapper {
* @returns Block number
*/
public async getBlockNumberAsync(): Promise<number> {
- const blockNumber = await promisify<number>(this._web3.eth.getBlockNumber)();
- return blockNumber;
+ const blockNumberHex = await this._sendRawPayloadAsync<string>({
+ method: 'eth_blockNumber',
+ params: [],
+ });
+ const blockNumber = utils.convertHexToNumberOrNull(blockNumberHex);
+ return blockNumber as number;
}
/**
* Fetch a specific Ethereum block without transaction data
@@ -241,10 +324,18 @@ export class Web3Wrapper {
* @returns The requested block without transaction data
*/
public async getBlockAsync(blockParam: string | BlockParam): Promise<BlockWithoutTransactionData> {
+ Web3Wrapper._assertBlockParamOrString(blockParam);
+ const encodedBlockParam = marshaller.marshalBlockParam(blockParam);
+ const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber';
const shouldIncludeTransactionData = false;
- const blockWithoutTransactionData = await promisify<BlockWithoutTransactionData>(this._web3.eth.getBlock)(
- blockParam,
- shouldIncludeTransactionData,
+ const blockWithoutTransactionDataWithHexValues = await this._sendRawPayloadAsync<
+ BlockWithoutTransactionDataRPC
+ >({
+ method,
+ params: [encodedBlockParam, shouldIncludeTransactionData],
+ });
+ const blockWithoutTransactionData = marshaller.unmarshalIntoBlockWithoutTransactionData(
+ blockWithoutTransactionDataWithHexValues,
);
return blockWithoutTransactionData;
}
@@ -254,12 +345,21 @@ export class Web3Wrapper {
* @returns The requested block with transaction data
*/
public async getBlockWithTransactionDataAsync(blockParam: string | BlockParam): Promise<BlockWithTransactionData> {
+ Web3Wrapper._assertBlockParamOrString(blockParam);
+ let encodedBlockParam = blockParam;
+ if (_.isNumber(blockParam)) {
+ encodedBlockParam = utils.numberToHex(blockParam);
+ }
+ const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber';
const shouldIncludeTransactionData = true;
- const blockWithTransactionData = await promisify<BlockWithTransactionData>(this._web3.eth.getBlock)(
- blockParam,
- shouldIncludeTransactionData,
+ const blockWithTransactionDataWithHexValues = await this._sendRawPayloadAsync<BlockWithTransactionDataRPC>({
+ method,
+ params: [encodedBlockParam, shouldIncludeTransactionData],
+ });
+ const blockWithoutTransactionData = marshaller.unmarshalIntoBlockWithTransactionData(
+ blockWithTransactionDataWithHexValues,
);
- return blockWithTransactionData;
+ return blockWithoutTransactionData;
}
/**
* Fetch a block's timestamp
@@ -267,6 +367,7 @@ export class Web3Wrapper {
* @returns The block's timestamp
*/
public async getBlockTimestampAsync(blockParam: string | BlockParam): Promise<number> {
+ Web3Wrapper._assertBlockParamOrString(blockParam);
const { timestamp } = await this.getBlockAsync(blockParam);
return timestamp;
}
@@ -275,7 +376,10 @@ export class Web3Wrapper {
* @returns Available user addresses
*/
public async getAvailableAddressesAsync(): Promise<string[]> {
- const addresses = await promisify<string[]>(this._web3.eth.getAccounts)();
+ const addresses = await this._sendRawPayloadAsync<string>({
+ method: 'eth_accounts',
+ params: [],
+ });
const normalizedAddresses = _.map(addresses, address => address.toLowerCase());
return normalizedAddresses;
}
@@ -293,6 +397,7 @@ export class Web3Wrapper {
* @returns Whether the revert was successful
*/
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
+ assert.isNumber('snapshotId', snapshotId);
const didRevert = await this._sendRawPayloadAsync<boolean>({ method: 'evm_revert', params: [snapshotId] });
return didRevert;
}
@@ -308,6 +413,7 @@ export class Web3Wrapper {
* @param timeDelta Amount of time to add in seconds
*/
public async increaseTimeAsync(timeDelta: number): Promise<number> {
+ assert.isNumber('timeDelta', timeDelta);
// Detect Geth vs. Ganache and use appropriate endpoint.
const version = await this.getNodeVersionAsync();
if (_.includes(version, uniqueVersionIds.geth)) {
@@ -326,11 +432,11 @@ export class Web3Wrapper {
public async getLogsAsync(filter: FilterObject): Promise<LogEntry[]> {
let fromBlock = filter.fromBlock;
if (_.isNumber(fromBlock)) {
- fromBlock = this._web3.toHex(fromBlock);
+ fromBlock = utils.numberToHex(fromBlock);
}
let toBlock = filter.toBlock;
if (_.isNumber(toBlock)) {
- toBlock = this._web3.toHex(toBlock);
+ toBlock = utils.numberToHex(toBlock);
}
const serializedFilter = {
...filter,
@@ -338,30 +444,27 @@ export class Web3Wrapper {
toBlock,
};
const payload = {
- jsonrpc: '2.0',
method: 'eth_getLogs',
params: [serializedFilter],
};
const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload);
- const formattedLogs = _.map(rawLogs, this._formatLog.bind(this));
+ const formattedLogs = _.map(rawLogs, marshaller.unmarshalLog.bind(marshaller));
return formattedLogs;
}
/**
- * Get a Web3 contract factory instance for a given ABI
- * @param abi Smart contract ABI
- * @returns Web3 contract factory which can create Web3 Contract instances from the supplied ABI
- */
- public getContractFromAbi(abi: ContractAbi): Web3.Contract<any> {
- const web3Contract = this._web3.eth.contract(abi);
- return web3Contract;
- }
- /**
* Calculate the estimated gas cost for a given transaction
* @param txData Transaction data
* @returns Estimated gas cost
*/
public async estimateGasAsync(txData: Partial<TxData>): Promise<number> {
- const gas = await promisify<number>(this._web3.eth.estimateGas)(txData);
+ assert.doesConformToSchema('txData', txData, schemas.txDataSchema, [
+ schemas.addressSchema,
+ schemas.numberSchema,
+ schemas.jsNumber,
+ ]);
+ const txDataHex = marshaller.marshalTxData(txData);
+ const gasHex = await this._sendRawPayloadAsync<string>({ method: 'eth_estimateGas', params: [txDataHex] });
+ const gas = utils.convertHexToNumber(gasHex);
return gas;
}
/**
@@ -371,7 +474,20 @@ export class Web3Wrapper {
* @returns The raw call result
*/
public async callAsync(callData: CallData, defaultBlock?: BlockParam): Promise<string> {
- const rawCallResult = await promisify<string>(this._web3.eth.call)(callData, defaultBlock);
+ assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
+ schemas.addressSchema,
+ schemas.numberSchema,
+ schemas.jsNumber,
+ ]);
+ if (!_.isUndefined(defaultBlock)) {
+ Web3Wrapper._assertBlockParam(defaultBlock);
+ }
+ const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
+ const callDataHex = marshaller.marshalCallData(callData);
+ const rawCallResult = await this._sendRawPayloadAsync<string>({
+ method: 'eth_call',
+ params: [callDataHex, marshalledDefaultBlock],
+ });
if (rawCallResult === '0x') {
throw new Error('Contract call failed (returned null)');
}
@@ -383,7 +499,13 @@ export class Web3Wrapper {
* @returns Transaction hash
*/
public async sendTransactionAsync(txData: TxData): Promise<string> {
- const txHash = await promisify<string>(this._web3.eth.sendTransaction)(txData);
+ assert.doesConformToSchema('txData', txData, schemas.txDataSchema, [
+ schemas.addressSchema,
+ schemas.numberSchema,
+ schemas.jsNumber,
+ ]);
+ const txDataHex = marshaller.marshalTxData(txData);
+ const txHash = await this._sendRawPayloadAsync<string>({ method: 'eth_sendTransaction', params: [txDataHex] });
return txHash;
}
/**
@@ -402,6 +524,11 @@ export class Web3Wrapper {
pollingIntervalMs: number = 1000,
timeoutMs?: number,
): Promise<TransactionReceiptWithDecodedLogs> {
+ assert.isHexString('txHash', txHash);
+ assert.isNumber('pollingIntervalMs', pollingIntervalMs);
+ if (!_.isUndefined(timeoutMs)) {
+ assert.isNumber('timeoutMs', timeoutMs);
+ }
// Immediately check if the transaction has already been mined.
let transactionReceipt = await this.getTransactionReceiptAsync(txHash);
if (!_.isNull(transactionReceipt)) {
@@ -487,10 +614,25 @@ export class Web3Wrapper {
* @param blockNumber The block number to reset to.
*/
public async setHeadAsync(blockNumber: number): Promise<void> {
- await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [this._web3.toHex(blockNumber)] });
+ assert.isNumber('blockNumber', blockNumber);
+ await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [utils.numberToHex(blockNumber)] });
+ }
+ /**
+ * Returns either NodeType.Geth or NodeType.Ganache depending on the type of
+ * the backing Ethereum node. Throws for any other type of node.
+ */
+ public async getNodeTypeAsync(): Promise<NodeType> {
+ const version = await this.getNodeVersionAsync();
+ if (_.includes(version, uniqueVersionIds.geth)) {
+ return NodeType.Geth;
+ } else if (_.includes(version, uniqueVersionIds.ganache)) {
+ return NodeType.Ganache;
+ } else {
+ throw new Error(`Unknown client version: ${version}`);
+ }
}
private async _sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> {
- const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider);
+ const sendAsync = this._provider.sendAsync.bind(this._provider);
const payloadWithDefaults = {
id: this._jsonRpcRequestId++,
params: [],
@@ -501,34 +643,4 @@ export class Web3Wrapper {
const result = response.result;
return result;
}
- private _normalizeTxReceiptStatus(status: undefined | null | string | 0 | 1): null | 0 | 1 {
- // Transaction status might have four values
- // undefined - Testrpc and other old clients
- // null - New clients on old transactions
- // number - Parity
- // hex - Geth
- if (_.isString(status)) {
- return this._web3.toDecimal(status) as 0 | 1;
- } else if (_.isUndefined(status)) {
- return null;
- } else {
- return status;
- }
- }
- private _formatLog(rawLog: RawLogEntry): LogEntry {
- const formattedLog = {
- ...rawLog,
- logIndex: this._hexToDecimal(rawLog.logIndex),
- blockNumber: this._hexToDecimal(rawLog.blockNumber),
- transactionIndex: this._hexToDecimal(rawLog.transactionIndex),
- };
- return formattedLog;
- }
- private _hexToDecimal(hex: string | null): number | null {
- if (_.isNull(hex)) {
- return null;
- }
- const decimal = this._web3.toDecimal(hex);
- return decimal;
- }
} // tslint:disable-line:max-file-line-count
diff --git a/packages/web3-wrapper/test/web3_wrapper_test.ts b/packages/web3-wrapper/test/web3_wrapper_test.ts
index 35eab3aa2..b4fd8bb44 100644
--- a/packages/web3-wrapper/test/web3_wrapper_test.ts
+++ b/packages/web3-wrapper/test/web3_wrapper_test.ts
@@ -1,18 +1,27 @@
import * as chai from 'chai';
+import { BlockParamLiteral } from 'ethereum-types';
import * as Ganache from 'ganache-core';
+import * as _ from 'lodash';
import 'mocha';
-import { Web3Wrapper } from '../src';
+import { utils } from '../src/utils';
+import { Web3Wrapper } from '../src/web3_wrapper';
import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const { expect } = chai;
+const NUM_GANACHE_ADDRESSES = 10;
+
describe('Web3Wrapper tests', () => {
const NETWORK_ID = 50;
const provider = Ganache.provider({ network_id: NETWORK_ID });
const web3Wrapper = new Web3Wrapper(provider);
+ let addresses: string[];
+ before(async () => {
+ addresses = await web3Wrapper.getAvailableAddressesAsync();
+ });
describe('#isAddress', () => {
it('correctly checks if a string is a valid ethereum address', () => {
expect(Web3Wrapper.isAddress('0x0')).to.be.false();
@@ -36,4 +45,88 @@ describe('Web3Wrapper tests', () => {
expect(networkId).to.be.equal(NETWORK_ID);
});
});
+ describe('#getNetworkIdAsync', () => {
+ it('gets the network id', async () => {
+ const networkId = await web3Wrapper.getNetworkIdAsync();
+ expect(networkId).to.be.equal(NETWORK_ID);
+ });
+ });
+ describe('#getAvailableAddressesAsync', () => {
+ it('gets the available addresses', async () => {
+ const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
+ expect(availableAddresses.length).to.be.equal(NUM_GANACHE_ADDRESSES);
+ expect(Web3Wrapper.isAddress(availableAddresses[0])).to.equal(true);
+ });
+ });
+ describe('#getBalanceInWeiAsync', () => {
+ it('gets the users balance in wei', async () => {
+ const secondAccount = addresses[1];
+ const balanceInWei = await web3Wrapper.getBalanceInWeiAsync(secondAccount);
+ const tenEthInWei = 100000000000000000000;
+ expect(balanceInWei).to.be.bignumber.equal(tenEthInWei);
+ });
+ it('should throw if supplied owner not an Ethereum address hex string', async () => {
+ const invalidEthAddress = 'deadbeef';
+ expect(web3Wrapper.getBalanceInWeiAsync(invalidEthAddress)).to.eventually.to.be.rejected();
+ });
+ });
+ describe('#signMessageAsync', () => {
+ it('should sign message', async () => {
+ const message = '0xdeadbeef';
+ const signer = addresses[1];
+ const signature = await web3Wrapper.signMessageAsync(signer, message);
+ const signatureLength = 132;
+ expect(signature.length).to.be.equal(signatureLength);
+ });
+ });
+ describe('#getBlockNumberAsync', () => {
+ it('get block number', async () => {
+ const blockNumber = await web3Wrapper.getBlockNumberAsync();
+ expect(typeof blockNumber).to.be.equal('number');
+ });
+ });
+ describe('#getBlockAsync', () => {
+ it('gets block when supplied a valid BlockParamLiteral value', async () => {
+ const blockParamLiteral = BlockParamLiteral.Earliest;
+ const block = await web3Wrapper.getBlockAsync(blockParamLiteral);
+ expect(block.number).to.be.equal(0);
+ expect(utils.isBigNumber(block.difficulty)).to.equal(true);
+ expect(_.isNumber(block.gasLimit)).to.equal(true);
+ });
+ it('gets block when supplied a block number', async () => {
+ const blockParamLiteral = 0;
+ const block = await web3Wrapper.getBlockAsync(blockParamLiteral);
+ expect(block.number).to.be.equal(0);
+ });
+ it('gets block when supplied a block hash', async () => {
+ const blockParamLiteral = 0;
+ const block = await web3Wrapper.getBlockAsync(blockParamLiteral);
+ const sameBlock = await web3Wrapper.getBlockAsync(block.hash as string);
+ expect(sameBlock.number).to.be.equal(0);
+ });
+ it('should throw if supplied invalid blockParam value', async () => {
+ const invalidBlockParam = 'deadbeef';
+ expect(web3Wrapper.getBlockAsync(invalidBlockParam)).to.eventually.to.be.rejected();
+ });
+ });
+ describe('#getBlockWithTransactionDataAsync', () => {
+ it('gets block when supplied a valid BlockParamLiteral value', async () => {
+ const blockParamLiteral = BlockParamLiteral.Earliest;
+ const block = await web3Wrapper.getBlockWithTransactionDataAsync(blockParamLiteral);
+ expect(block.number).to.be.equal(0);
+ expect(utils.isBigNumber(block.difficulty)).to.equal(true);
+ expect(_.isNumber(block.gasLimit)).to.equal(true);
+ });
+ it('should throw if supplied invalid blockParam value', async () => {
+ const invalidBlockParam = 'deadbeef';
+ expect(web3Wrapper.getBlockWithTransactionDataAsync(invalidBlockParam)).to.eventually.to.be.rejected();
+ });
+ });
+ describe('#getBlockTimestampAsync', () => {
+ it('gets block timestamp', async () => {
+ const blockParamLiteral = BlockParamLiteral.Earliest;
+ const timestamp = await web3Wrapper.getBlockTimestampAsync(blockParamLiteral);
+ expect(_.isNumber(timestamp)).to.be.equal(true);
+ });
+ });
});
diff --git a/packages/website/package.json b/packages/website/package.json
index c7b689356..a5768a60b 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -38,6 +38,7 @@
"lodash": "^4.17.4",
"material-ui": "^0.17.1",
"moment": "2.21.0",
+ "numeral": "^2.0.6",
"polished": "^1.9.2",
"query-string": "^6.0.0",
"react": "15.6.1",
@@ -57,8 +58,7 @@
"styled-components": "^3.3.0",
"thenby": "^1.2.3",
"truffle-contract": "2.0.1",
- "web3": "^0.20.0",
- "web3-provider-engine": "^14.0.4",
+ "web3-provider-engine": "14.0.6",
"whatwg-fetch": "^2.0.3",
"xml-js": "^1.6.4"
},
@@ -71,6 +71,7 @@
"@types/lodash": "4.14.104",
"@types/material-ui": "0.18.0",
"@types/node": "^8.0.53",
+ "@types/numeral": "^0.0.22",
"@types/query-string": "^5.1.0",
"@types/react": "16.3.13",
"@types/react-copy-to-clipboard": "^4.2.0",
diff --git a/packages/website/public/images/lock_icon.svg b/packages/website/public/images/lock_icon.svg
new file mode 100644
index 000000000..83e8191a1
--- /dev/null
+++ b/packages/website/public/images/lock_icon.svg
@@ -0,0 +1,3 @@
+<svg width="26" height="32" viewBox="0 0 26 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6.47619 0C3.79509 0 1.60489 2.21216 1.60489 4.92014V6.33135C0.717479 6.33135 -3.60127e-08 7.05602 -3.60127e-08 7.95232V14.379C-3.60127e-08 15.2753 0.717479 16 1.60489 16H11.3475C12.2349 16 12.9524 15.2753 12.9524 14.379V7.95232C12.9524 7.05602 12.2349 6.33135 11.3475 6.33135V4.92014C11.3475 2.21216 9.1573 0 6.47619 0ZM9.6482 6.33135H3.30418V4.92014C3.30418 3.16567 4.72026 1.71633 6.47619 1.71633C8.23213 1.71633 9.6482 3.16567 9.6482 4.92014V6.33135Z" transform="scale(2)" fill="black"/>
+</svg>
diff --git a/packages/website/public/images/setup_account_icon.svg b/packages/website/public/images/setup_account_icon.svg
new file mode 100644
index 000000000..eaa5b2fd6
--- /dev/null
+++ b/packages/website/public/images/setup_account_icon.svg
@@ -0,0 +1,3 @@
+<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5 9C16.5 13.1421 13.1421 16.5 9 16.5C4.85791 16.5 1.5 13.1421 1.5 9C1.5 4.85791 4.85791 1.5 9 1.5C13.1421 1.5 16.5 4.85791 16.5 9ZM18 9C18 13.9706 13.9707 18 9 18C4.0293 18 0 13.9706 0 9C0 4.02942 4.0293 0 9 0C13.9707 0 18 4.02942 18 9ZM9.21973 5.7196C9.5127 5.42664 9.9873 5.42664 10.2803 5.7196L13.0806 8.51953C13.373 8.8125 13.373 9.28735 13.0806 9.5802L10.2803 12.3802C9.9873 12.6731 9.5127 12.6731 9.21973 12.3802C8.92676 12.0873 8.92676 11.6124 9.21973 11.3196L10.7393 9.7998H4.75C4.33594 9.7998 4 9.46399 4 9.0498C4 8.63562 4.33594 8.2998 4.75 8.2998H10.7393L9.21973 6.78015C8.92676 6.4873 8.92676 6.01245 9.21973 5.7196Z" transform="scale(2)" fill="#3289F1"/>
+</svg>
diff --git a/packages/website/public/images/team/alexbrowne.png b/packages/website/public/images/team/alexbrowne.png
new file mode 100644
index 000000000..76a61913e
--- /dev/null
+++ b/packages/website/public/images/team/alexbrowne.png
Binary files differ
diff --git a/packages/website/public/images/toshi_logo.jpg b/packages/website/public/images/toshi_logo.jpg
new file mode 100644
index 000000000..3cf451d24
--- /dev/null
+++ b/packages/website/public/images/toshi_logo.jpg
Binary files differ
diff --git a/packages/website/public/index.html b/packages/website/public/index.html
index 4c0985c71..060f2c3c2 100644
--- a/packages/website/public/index.html
+++ b/packages/website/public/index.html
@@ -70,7 +70,18 @@
})(document, 'script', 'twitter-wjs');
</script>
<!-- End Twitter SDK -->
-
+ <!-- Hotjar Tracking Code for https://0xproject.com/ -->
+ <script>
+ (function (h, o, t, j, a, r) {
+ h.hj = h.hj || function () { (h.hj.q = h.hj.q || []).push(arguments) };
+ h._hjSettings = { hjid: 935597, hjsv: 6 };
+ a = o.getElementsByTagName('head')[0];
+ r = o.createElement('script'); r.async = 1;
+ r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
+ a.appendChild(r);
+ })(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
+ </script>
+ <!-- End Hotjar Tracking Code -->
<!-- Main -->
<script type="text/javascript" crossorigin="anonymous" src="/bundle.js" charset="utf-8"></script>
</body>
diff --git a/packages/website/translations/english.json b/packages/website/translations/english.json
index 04fb0507a..d94dbb29e 100644
--- a/packages/website/translations/english.json
+++ b/packages/website/translations/english.json
@@ -76,5 +76,6 @@
"WEBSITE": "website",
"DEVELOPERS": "developers",
"HOME": "home",
- "ROCKETCHAT": "rocket.chat"
+ "ROCKETCHAT": "rocket.chat",
+ "TRADE_CALL_TO_ACTION": "trade on 0x"
}
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts
index d18c34c32..cc2afa28a 100644
--- a/packages/website/ts/blockchain.ts
+++ b/packages/website/ts/blockchain.ts
@@ -12,10 +12,10 @@ import {
import { isValidOrderHash, signOrderHashAsync } from '@0xproject/order-utils';
import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
import {
- InjectedWeb3Subprovider,
ledgerEthereumBrowserClientFactoryAsync,
LedgerSubprovider,
RedundantSubprovider,
+ SignerSubprovider,
Subprovider,
} from '@0xproject/subproviders';
import {
@@ -46,6 +46,7 @@ import {
Fill,
InjectedProviderObservable,
InjectedProviderUpdate,
+ InjectedWeb3,
Order as PortalOrder,
Providers,
ProviderType,
@@ -59,7 +60,6 @@ import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter';
import { utils } from 'ts/utils/utils';
-import Web3 = require('web3');
import ProviderEngine = require('web3-provider-engine');
import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
@@ -73,6 +73,8 @@ const providerToName: { [provider: string]: string } = {
[Providers.Metamask]: constants.PROVIDER_NAME_METAMASK,
[Providers.Parity]: constants.PROVIDER_NAME_PARITY_SIGNER,
[Providers.Mist]: constants.PROVIDER_NAME_MIST,
+ [Providers.Toshi]: constants.PROVIDER_NAME_TOSHI,
+ [Providers.Cipher]: constants.PROVIDER_NAME_CIPHER,
};
export class Blockchain {
@@ -95,8 +97,19 @@ export class Blockchain {
}
return providerNameIfExists;
}
- private static _getInjectedWeb3(): any {
- return (window as any).web3;
+ private static _getInjectedWeb3(): InjectedWeb3 {
+ const injectedWeb3IfExists = (window as any).web3;
+ // Our core assumptions about the injected web3 object is that it has the following
+ // properties and methods.
+ if (
+ _.isUndefined(injectedWeb3IfExists) ||
+ _.isUndefined(injectedWeb3IfExists.version) ||
+ _.isUndefined(injectedWeb3IfExists.version.getNetwork) ||
+ _.isUndefined(injectedWeb3IfExists.currentProvider)
+ ) {
+ return undefined;
+ }
+ return injectedWeb3IfExists;
}
private static async _getInjectedWeb3ProviderNetworkIdIfExistsAsync(): Promise<number | undefined> {
// Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in
@@ -117,7 +130,7 @@ export class Blockchain {
return networkIdIfExists;
}
private static async _getProviderAsync(
- injectedWeb3: Web3,
+ injectedWeb3: InjectedWeb3,
networkIdIfExists: number,
shouldUserLedgerProvider: boolean = false,
): Promise<[Provider, LedgerSubprovider | undefined]> {
@@ -151,7 +164,7 @@ export class Blockchain {
// We catch all requests involving a users account and send it to the injectedWeb3
// instance. All other requests go to the public hosted node.
const provider = new ProviderEngine();
- provider.addProvider(new InjectedWeb3Subprovider(injectedWeb3.currentProvider));
+ provider.addProvider(new SignerSubprovider(injectedWeb3.currentProvider));
provider.addProvider(new FilterSubprovider());
const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => {
return new RpcSubprovider({
@@ -832,10 +845,10 @@ export class Blockchain {
this._dispatcher.updateNetworkId(networkId);
await this._rehydrateStoreWithContractEventsAsync();
}
- private _updateProviderName(injectedWeb3: Web3): void {
- const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
+ private _updateProviderName(injectedWeb3IfExists: InjectedWeb3): void {
+ const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3IfExists);
const providerName = doesInjectedWeb3Exist
- ? Blockchain._getNameGivenProvider(injectedWeb3.currentProvider)
+ ? Blockchain._getNameGivenProvider(injectedWeb3IfExists.currentProvider)
: constants.PROVIDER_NAME_PUBLIC;
this._dispatcher.updateInjectedProviderName(providerName);
}
diff --git a/packages/website/ts/blockchain_watcher.ts b/packages/website/ts/blockchain_watcher.ts
index df5f73fd1..4b23aa98a 100644
--- a/packages/website/ts/blockchain_watcher.ts
+++ b/packages/website/ts/blockchain_watcher.ts
@@ -10,6 +10,7 @@ export class BlockchainWatcher {
private _watchBalanceIntervalId: NodeJS.Timer;
private _prevUserEtherBalanceInWei?: BigNumber;
private _prevUserAddressIfExists: string;
+ private _prevNodeVersionIfExists: string;
constructor(dispatcher: Dispatcher, web3Wrapper: Web3Wrapper, shouldPollUserAddress: boolean) {
this._dispatcher = dispatcher;
this._shouldPollUserAddress = shouldPollUserAddress;
@@ -43,11 +44,9 @@ export class BlockchainWatcher {
);
}
private async _updateBalanceAsync(): Promise<void> {
- let prevNodeVersion: string;
- // Check for node version changes
const currentNodeVersion = await this._web3Wrapper.getNodeVersionAsync();
- if (currentNodeVersion !== prevNodeVersion) {
- prevNodeVersion = currentNodeVersion;
+ if (this._prevNodeVersionIfExists !== currentNodeVersion) {
+ this._prevNodeVersionIfExists = currentNodeVersion;
this._dispatcher.updateNodeVersion(currentNodeVersion);
}
diff --git a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
index 9ac78e80e..7b09cc92c 100644
--- a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
+++ b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
@@ -103,7 +103,6 @@ export class EthWethConversionDialog extends React.Component<
shouldCheckAllowance={false}
onChange={this._onValueChange.bind(this)}
amount={this.state.value}
- onVisitBalancesPageClick={this.props.onCancelled}
/>
) : (
<EthAmountInput
@@ -112,7 +111,6 @@ export class EthWethConversionDialog extends React.Component<
onChange={this._onValueChange.bind(this)}
shouldCheckBalance={true}
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- onVisitBalancesPageClick={this.props.onCancelled}
/>
)}
<div className="pt1" style={{ fontSize: 12 }}>
diff --git a/packages/website/ts/components/dialogs/send_dialog.tsx b/packages/website/ts/components/dialogs/send_dialog.tsx
index 421f18b4f..8a98fdf69 100644
--- a/packages/website/ts/components/dialogs/send_dialog.tsx
+++ b/packages/website/ts/components/dialogs/send_dialog.tsx
@@ -80,7 +80,6 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
shouldCheckAllowance={false}
onChange={this._onValueChange.bind(this)}
amount={this.state.value}
- onVisitBalancesPageClick={this.props.onCancelled}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/>
</div>
diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx
index 968609030..f23beb436 100644
--- a/packages/website/ts/components/inputs/balance_bounded_input.tsx
+++ b/packages/website/ts/components/inputs/balance_bounded_input.tsx
@@ -3,9 +3,8 @@ import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import TextField from 'material-ui/TextField';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import { RequiredLabel } from 'ts/components/ui/required_label';
-import { ValidatedBigNumberCallback, WebsitePaths } from 'ts/types';
+import { ValidatedBigNumberCallback } from 'ts/types';
import { utils } from 'ts/utils/utils';
interface BalanceBoundedInputProps {
@@ -18,8 +17,6 @@ interface BalanceBoundedInputProps {
shouldShowIncompleteErrs?: boolean;
shouldCheckBalance: boolean;
validate?: (amount: BigNumber) => React.ReactNode;
- onVisitBalancesPageClick?: () => void;
- shouldHideVisitBalancesLink?: boolean;
isDisabled?: boolean;
shouldShowErrs?: boolean;
shouldShowUnderline?: boolean;
@@ -35,7 +32,6 @@ interface BalanceBoundedInputState {
export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> {
public static defaultProps: Partial<BalanceBoundedInputProps> = {
shouldShowIncompleteErrs: false,
- shouldHideVisitBalancesLink: false,
isDisabled: false,
shouldShowErrs: true,
hintText: 'amount',
@@ -124,38 +120,11 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp
return 'Cannot be zero';
}
if (this.props.shouldCheckBalance && amount.gt(balance)) {
- return <span>Insufficient balance. {this._renderIncreaseBalanceLink()}</span>;
+ return <span>Insufficient balance.</span>;
}
const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
return errMsg;
}
- private _renderIncreaseBalanceLink(): React.ReactNode {
- if (this.props.shouldHideVisitBalancesLink) {
- return null;
- }
-
- const increaseBalanceText = 'Increase balance';
- const linkStyle = {
- cursor: 'pointer',
- color: colors.darkestGrey,
- textDecoration: 'underline',
- display: 'inline',
- };
- if (_.isUndefined(this.props.onVisitBalancesPageClick)) {
- return (
- <Link to={`${WebsitePaths.Portal}/balances`} style={linkStyle}>
- {increaseBalanceText}
- </Link>
- );
- } else {
- return (
- <div onClick={this.props.onVisitBalancesPageClick} style={linkStyle}>
- {increaseBalanceText}
- </div>
- );
- }
- }
-
private _setAmountState(amount: string, balance: BigNumber, callback: () => void = _.noop): void {
const errorMsg = this._validate(amount, balance);
this.props.onErrorMsgChange(errorMsg);
diff --git a/packages/website/ts/components/inputs/eth_amount_input.tsx b/packages/website/ts/components/inputs/eth_amount_input.tsx
index 1f0f27410..552d4277a 100644
--- a/packages/website/ts/components/inputs/eth_amount_input.tsx
+++ b/packages/website/ts/components/inputs/eth_amount_input.tsx
@@ -14,9 +14,7 @@ interface EthAmountInputProps {
onChange: ValidatedBigNumberCallback;
onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
shouldShowIncompleteErrs: boolean;
- onVisitBalancesPageClick?: () => void;
shouldCheckBalance: boolean;
- shouldHideVisitBalancesLink?: boolean;
shouldShowErrs?: boolean;
shouldShowUnderline?: boolean;
style?: React.CSSProperties;
@@ -46,8 +44,6 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou
onErrorMsgChange={this.props.onErrorMsgChange}
shouldCheckBalance={this.props.shouldCheckBalance}
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
- onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
- shouldHideVisitBalancesLink={this.props.shouldHideVisitBalancesLink}
hintText={this.props.hintText}
shouldShowErrs={this.props.shouldShowErrs}
shouldShowUnderline={this.props.shouldShowUnderline}
diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx
index a67120320..93ef516cf 100644
--- a/packages/website/ts/components/inputs/token_amount_input.tsx
+++ b/packages/website/ts/components/inputs/token_amount_input.tsx
@@ -21,7 +21,6 @@ interface TokenAmountInputProps {
shouldCheckAllowance: boolean;
onChange: ValidatedBigNumberCallback;
onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
- onVisitBalancesPageClick?: () => void;
lastForceTokenStateRefetch: number;
shouldShowErrs?: boolean;
shouldShowUnderline?: boolean;
@@ -88,7 +87,6 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
validate={this._validate.bind(this)}
shouldCheckBalance={this.props.shouldCheckBalance}
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
- onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
isDisabled={!this.state.isBalanceAndAllowanceLoaded}
hintText={this.props.hintText}
shouldShowErrs={this.props.shouldShowErrs}
diff --git a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
index a95c464af..d618c8318 100644
--- a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
+++ b/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
@@ -1,19 +1,42 @@
import { colors } from '@0xproject/react-shared';
-import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
import * as React from 'react';
import { Container } from 'ts/components/ui/container';
+import { Image } from 'ts/components/ui/image';
import { Text } from 'ts/components/ui/text';
+import { utils } from 'ts/utils/utils';
export interface InstallWalletOnboardingStepProps {}
-export const InstallWalletOnboardingStep: React.StatelessComponent<InstallWalletOnboardingStepProps> = () => (
- <div className="flex items-center flex-column">
- <Text>
- Before you begin, you need to connect to a wallet. This will be used across all 0x relayers and dApps.
- </Text>
- <Container marginTop="15px" marginBottom="15px">
- <ActionAccountBalanceWallet style={{ width: '50px', height: '50px' }} color={colors.orange} />
- </Container>
- <Text>Please refresh the page once you've done this to continue!</Text>
- </div>
-);
+export const InstallWalletOnboardingStep: React.StatelessComponent<InstallWalletOnboardingStepProps> = () => {
+ const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile();
+ const followupText = isOnMobile
+ ? `Please revisit this site in your mobile dApp browser to continue!`
+ : `Please refresh the page once you've done this to continue!`;
+ const downloadText = isOnMobile ? 'Get the Toshi Wallet' : 'Get the MetaMask extension';
+ return (
+ <div className="flex items-center flex-column">
+ <Text>First, you need to connect to a wallet. This will be used across all 0x relayers and dApps.</Text>
+ <Container className="flex items-center" marginTop="15px" marginBottom="15px">
+ <Image
+ height="50px"
+ width="50px"
+ borderRadius="22%"
+ src={isOnMobile ? '/images/toshi_logo.jpg' : '/images/metamask_icon.png'}
+ />
+ <Container marginLeft="10px">
+ <a href={downloadLink} target="_blank">
+ <Text
+ fontWeight={700}
+ fontSize="18px"
+ fontColor={colors.mediumBlue}
+ textDecorationLine="underline"
+ >
+ {downloadText}
+ </Text>
+ </a>
+ </Container>
+ </Container>
+ <Text>{followupText}</Text>
+ </div>
+ );
+};
diff --git a/packages/website/ts/components/onboarding/onboarding_card.tsx b/packages/website/ts/components/onboarding/onboarding_card.tsx
index 48e8ab022..ba5b3d6ea 100644
--- a/packages/website/ts/components/onboarding/onboarding_card.tsx
+++ b/packages/website/ts/components/onboarding/onboarding_card.tsx
@@ -39,7 +39,7 @@ export const OnboardingCard: React.StatelessComponent<OnboardingCardProps> = ({
borderRadius,
}) => (
<Island borderRadius={borderRadius}>
- <Container paddingRight="30px" paddingLeft="30px" maxWidth={350} paddingTop="15px" paddingBottom="15px">
+ <Container paddingRight="30px" paddingLeft="30px" paddingTop="15px" paddingBottom="15px">
<div className="flex flex-column">
<div className="flex justify-between">
<Title>{title}</Title>
diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx
index 1f4c6df82..c2b4a4ca7 100644
--- a/packages/website/ts/components/onboarding/onboarding_flow.tsx
+++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx
@@ -6,13 +6,29 @@ import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboardi
import { Animation } from 'ts/components/ui/animation';
import { Container } from 'ts/components/ui/container';
import { Overlay } from 'ts/components/ui/overlay';
+import { PointerDirection } from 'ts/components/ui/pointer';
import { zIndex } from 'ts/style/z_index';
-export interface Step {
+export interface FixedPositionSettings {
+ type: 'fixed';
+ top?: string;
+ bottom?: string;
+ left?: string;
+ right?: string;
+ pointerDirection?: PointerDirection;
+}
+
+export interface TargetPositionSettings {
+ type: 'target';
target: string;
+ placement: Placement;
+}
+
+export interface Step {
+ // Provide either a CSS selector, or fixed position settings. Only applies to desktop.
+ position: TargetPositionSettings | FixedPositionSettings;
title?: string;
content: React.ReactNode;
- placement?: Placement;
shouldHideBackButton?: boolean;
shouldHideNextButton?: boolean;
continueButtonDisplay?: ContinueButtonDisplay;
@@ -40,18 +56,30 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
return null;
}
let onboardingElement = null;
+ const currentStep = this._getCurrentStep();
if (this.props.isMobile) {
- onboardingElement = <Animation type="easeUpFromBottom">{this._renderOnboardignCard()}</Animation>;
- } else {
+ onboardingElement = <Animation type="easeUpFromBottom">{this._renderOnboardingCard()}</Animation>;
+ } else if (currentStep.position.type === 'target') {
+ const { placement, target } = currentStep.position;
onboardingElement = (
- <Popper
- referenceElement={this._getElementForStep()}
- placement={this._getCurrentStep().placement}
- positionFixed={true}
- >
+ <Popper referenceElement={document.querySelector(target)} placement={placement} positionFixed={true}>
{this._renderPopperChildren.bind(this)}
</Popper>
);
+ } else if (currentStep.position.type === 'fixed') {
+ const { top, right, bottom, left, pointerDirection } = currentStep.position;
+ onboardingElement = (
+ <Container
+ position="fixed"
+ zIndex={zIndex.aboveOverlay}
+ top={top}
+ right={right}
+ bottom={bottom}
+ left={left}
+ >
+ {this._renderToolTip(pointerDirection)}
+ </Container>
+ );
}
if (this.props.disableOverlay) {
return onboardingElement;
@@ -63,9 +91,6 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
</div>
);
}
- private _getElementForStep(): Element {
- return document.querySelector(this._getCurrentStep().target);
- }
private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode {
const customStyles = { zIndex: zIndex.aboveOverlay };
// On re-render, we want to re-center the popper.
@@ -76,7 +101,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
</div>
);
}
- private _renderToolTip(): React.ReactNode {
+ private _renderToolTip(pointerDirection?: PointerDirection): React.ReactNode {
const { steps, stepIndex } = this.props;
const step = steps[stepIndex];
const isLastStep = steps.length - 1 === stepIndex;
@@ -94,12 +119,13 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
continueButtonDisplay={step.continueButtonDisplay}
continueButtonText={step.continueButtonText}
onContinueButtonClick={step.onContinueButtonClick}
+ pointerDirection={pointerDirection}
/>
</Container>
);
}
- private _renderOnboardignCard(): React.ReactNode {
+ private _renderOnboardingCard(): React.ReactNode {
const { steps, stepIndex } = this.props;
const step = steps[stepIndex];
const isLastStep = steps.length - 1 === stepIndex;
diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
index 6bfa5c75f..1c2c92fd1 100644
--- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
+++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
@@ -9,7 +9,12 @@ import { AddEthOnboardingStep } from 'ts/components/onboarding/add_eth_onboardin
import { CongratsOnboardingStep } from 'ts/components/onboarding/congrats_onboarding_step';
import { InstallWalletOnboardingStep } from 'ts/components/onboarding/install_wallet_onboarding_step';
import { IntroOnboardingStep } from 'ts/components/onboarding/intro_onboarding_step';
-import { OnboardingFlow, Step } from 'ts/components/onboarding/onboarding_flow';
+import {
+ FixedPositionSettings,
+ OnboardingFlow,
+ Step,
+ TargetPositionSettings,
+} from 'ts/components/onboarding/onboarding_flow';
import { SetAllowancesOnboardingStep } from 'ts/components/onboarding/set_allowances_onboarding_step';
import { UnlockWalletOnboardingStep } from 'ts/components/onboarding/unlock_wallet_onboarding_step';
import {
@@ -45,8 +50,6 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
private _unlisten: () => void;
public componentDidMount(): void {
this._adjustStepIfShould();
- // Wait until the step is adjusted to decide whether we should show onboarding.
- setTimeout(this._autoStartOnboardingIfShould.bind(this), 1000);
// If there is a route change, just close onboarding.
this._unlisten = this.props.history.listen(() => this.props.updateIsRunning(false));
}
@@ -54,12 +57,14 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
this._unlisten();
}
public componentDidUpdate(prevProps: PortalOnboardingFlowProps): void {
- this._adjustStepIfShould();
- if (!prevProps.isRunning && this.props.isRunning) {
+ // Any one of steps 0-3 could be the starting step, and we only want to reset the scroll on the starting step.
+ if (this.props.isRunning && utils.isMobileWidth(this.props.screenWidth) && this.props.stepIndex < 3) {
// On mobile, make sure the wallet is completely visible.
- if (this.props.screenWidth === ScreenWidths.Sm) {
- document.querySelector('.wallet').scrollIntoView();
- }
+ document.querySelector('.wallet').scrollIntoView();
+ }
+ this._adjustStepIfShould();
+ if (!prevProps.blockchainIsLoaded && this.props.blockchainIsLoaded) {
+ this._autoStartOnboardingIfShould();
}
}
public render(): React.ReactNode {
@@ -76,56 +81,61 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
);
}
private _getSteps(): Step[] {
+ const nextToWalletPosition: TargetPositionSettings = {
+ type: 'target',
+ target: '.wallet',
+ placement: 'right',
+ };
+ const underMetamaskExtension: FixedPositionSettings = {
+ type: 'fixed',
+ top: '30px',
+ right: '10px',
+ pointerDirection: 'top',
+ };
const steps: Step[] = [
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: '0x Ecosystem Setup',
content: <InstallWalletOnboardingStep />,
- placement: 'right',
shouldHideBackButton: true,
shouldHideNextButton: true,
},
{
- target: '.wallet',
+ position: underMetamaskExtension,
title: '0x Ecosystem Setup',
content: <UnlockWalletOnboardingStep />,
- placement: 'right',
shouldHideBackButton: true,
shouldHideNextButton: true,
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: '0x Ecosystem Account Setup',
content: <IntroOnboardingStep />,
- placement: 'right',
shouldHideBackButton: true,
continueButtonDisplay: 'enabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 1: Add ETH',
content: (
<AddEthOnboardingStep userEthBalanceInWei={this.props.userEtherBalanceInWei || new BigNumber(0)} />
),
- placement: 'right',
continueButtonDisplay: this._userHasVisibleEth() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 2: Wrap ETH',
content: <WrapEthOnboardingStep1 />,
- placement: 'right',
continueButtonDisplay: 'enabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 2: Wrap ETH',
content: <WrapEthOnboardingStep2 />,
- placement: 'right',
continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 2: Wrap ETH',
content: (
<WrapEthOnboardingStep3
@@ -134,11 +144,10 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
}
/>
),
- placement: 'right',
continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 3: Unlock Tokens',
content: (
<SetAllowancesOnboardingStep
@@ -147,14 +156,12 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
doesUserHaveAllowancesForWethAndZrx={this._doesUserHaveAllowancesForWethAndZrx()}
/>
),
- placement: 'right',
continueButtonDisplay: this._doesUserHaveAllowancesForWethAndZrx() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: '🎉 The Ecosystem Awaits',
content: <CongratsOnboardingStep />,
- placement: 'right',
continueButtonDisplay: 'enabled',
shouldHideNextButton: true,
continueButtonText: 'Enter the 0x Ecosystem',
@@ -221,7 +228,7 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
}
private _autoStartOnboardingIfShould(): void {
if (
- (this.props.stepIndex === 0 && !this.props.isRunning) ||
+ (this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) ||
(!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded)
) {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
@@ -267,7 +274,7 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
);
}
private _handleFinalStepContinueClick(): void {
- if (utils.isMobile(this.props.screenWidth)) {
+ if (utils.isMobileWidth(this.props.screenWidth)) {
window.scrollTo(0, 0);
this.props.history.push('/portal');
}
diff --git a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
index 0039aa545..4ed7137d4 100644
--- a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
+++ b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
@@ -10,7 +10,7 @@ export const UnlockWalletOnboardingStep: React.StatelessComponent<UnlockWalletOn
<Container marginTop="15px" marginBottom="15px">
<img src="/images/metamask_icon.png" height="50px" width="50px" />
</Container>
- <Text center={true}>Unlock your metamask extension to get started.</Text>
+ <Text center={true}>Unlock your MetaMask extension to get started.</Text>
</div>
</div>
);
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
index 9c0cb866d..f983241fa 100644
--- a/packages/website/ts/components/portal/portal.tsx
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -1,7 +1,6 @@
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
-import Help from 'material-ui/svg-icons/action/help';
import * as React from 'react';
import * as DocumentTitle from 'react-document-title';
import { Link, Route, RouteComponentProps, Switch } from 'react-router-dom';
@@ -24,6 +23,7 @@ import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar';
import { TradeHistory } from 'ts/components/trade_history/trade_history';
import { Container } from 'ts/components/ui/container';
import { FlashMessage } from 'ts/components/ui/flash_message';
+import { Image } from 'ts/components/ui/image';
import { Text } from 'ts/components/ui/text';
import { Wallet } from 'ts/components/wallet/wallet';
import { GenerateOrderForm } from 'ts/containers/generate_order_form';
@@ -91,7 +91,7 @@ interface PortalState {
interface AccountManagementItem {
pathName: string;
- headerText: string;
+ headerText?: string;
render: () => React.ReactNode;
}
@@ -106,7 +106,7 @@ const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded);
const LEFT_COLUMN_WIDTH = 346;
const MENU_PADDING_LEFT = 185;
const LARGE_LAYOUT_MAX_WIDTH = 1200;
-const LARGE_LAYOUT_MARGIN = 30;
+const SIDE_PADDING = 20;
export class Portal extends React.Component<PortalProps, PortalState> {
private _blockchain: Blockchain;
@@ -225,7 +225,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
: TokenVisibility.TRACKED;
return (
<Container>
- <DocumentTitle title="0x Portal DApp" />
+ <DocumentTitle title="0x Portal" />
<TopBar
userAddress={this.props.userAddress}
networkId={this.props.networkId}
@@ -318,13 +318,17 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderWallet(): React.ReactNode {
- const isMobile = utils.isMobile(this.props.screenWidth);
+ const isMobile = utils.isMobileWidth(this.props.screenWidth);
// We need room to scroll down for mobile onboarding
- const marginBottom = isMobile ? '200px' : '15px';
+ const marginBottom = isMobile ? '250px' : '15px';
return (
<div>
<Container className="flex flex-column items-center">
- {isMobile && <Container marginBottom="20px">{this._renderStartOnboarding()}</Container>}
+ {isMobile && (
+ <Container marginTop="20px" marginBottom="20px">
+ {this._renderStartOnboarding()}
+ </Container>
+ )}
<Container marginBottom={marginBottom} width="100%">
<Wallet
style={
@@ -364,15 +368,15 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderStartOnboarding(): React.ReactNode {
- const isMobile = utils.isMobile(this.props.screenWidth);
+ const isMobile = utils.isMobileWidth(this.props.screenWidth);
const shouldStartOnboarding = !isMobile || this.props.location.pathname === `${WebsitePaths.Portal}/account`;
const startOnboarding = (
<Container className="flex items-center center">
- <Help style={{ width: '20px', height: '20px' }} color={colors.mediumBlue} />
- <Container marginLeft="8px">
- <Text fontColor={colors.mediumBlue} fontSize="16px" onClick={this._startOnboarding.bind(this)}>
- Learn how to set up your account
- </Text>
+ <Text fontColor={colors.mediumBlue} fontSize="16px" onClick={this._startOnboarding.bind(this)}>
+ Set up your account to start trading
+ </Text>
+ <Container marginLeft="8px" paddingTop="3px">
+ <Image src="/images/setup_account_icon.svg" height="20px" width="20x" />
</Container>
</Container>
);
@@ -402,7 +406,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
},
{
pathName: `${WebsitePaths.Portal}/account`,
- headerText: 'Your Account',
+ headerText: this._isSmallScreen() ? undefined : 'Your Account',
render: this._isSmallScreen() ? this._renderWallet.bind(this) : this._renderTokenBalances.bind(this),
},
{
@@ -445,7 +449,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
private _renderAccountManagementItem(item: AccountManagementItem): React.ReactNode {
return (
<Section
- header={<TextHeader labelText={item.headerText} />}
+ header={!_.isUndefined(item.headerText) && <TextHeader labelText={item.headerText} />}
body={<Loading isLoading={!this.props.blockchainIsLoaded} content={item.render()} />}
/>
);
@@ -527,15 +531,21 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderRelayerIndexSection(): React.ReactNode {
- return <Section header={<TextHeader labelText="0x Relayers" />} body={this._renderRelayerIndex()} />;
- }
- private _renderRelayerIndex(): React.ReactNode {
- const isMobile = utils.isMobile(this.props.screenWidth);
+ const isMobile = utils.isMobileWidth(this.props.screenWidth);
return (
- <Container className="flex flex-column items-center">
- {isMobile && <Container marginBottom="20px">{this._renderStartOnboarding()}</Container>}
- <RelayerIndex networkId={this.props.networkId} screenWidth={this.props.screenWidth} />
- </Container>
+ <Section
+ header={!isMobile && <TextHeader labelText="0x Relayers" />}
+ body={
+ <Container className="flex flex-column items-center">
+ {isMobile && (
+ <Container marginTop="20px" marginBottom="20px">
+ {this._renderStartOnboarding()}
+ </Container>
+ )}
+ <RelayerIndex networkId={this.props.networkId} screenWidth={this.props.screenWidth} />
+ </Container>
+ }
+ />
);
}
private _renderNotFoundMessage(): React.ReactNode {
@@ -685,19 +695,19 @@ interface LargeLayoutProps {
}
const LargeLayout = (props: LargeLayoutProps) => {
return (
- <Container className="mx-auto flex flex-center" maxWidth={LARGE_LAYOUT_MAX_WIDTH}>
+ <Container
+ className="mx-auto flex flex-center"
+ maxWidth={LARGE_LAYOUT_MAX_WIDTH}
+ paddingLeft={SIDE_PADDING}
+ paddingRight={SIDE_PADDING}
+ >
<div className="flex-last">
- <Container
- width={LEFT_COLUMN_WIDTH}
- position="fixed"
- zIndex={zIndex.aboveTopBar}
- marginLeft={LARGE_LAYOUT_MARGIN}
- >
+ <Container width={LEFT_COLUMN_WIDTH} position="fixed" zIndex={zIndex.aboveTopBar}>
{props.left}
</Container>
</div>
- <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH + LARGE_LAYOUT_MARGIN}>
- <Container className="flex-auto" marginLeft={LARGE_LAYOUT_MARGIN} marginRight={LARGE_LAYOUT_MARGIN}>
+ <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH}>
+ <Container className="flex-auto" marginLeft={SIDE_PADDING}>
{props.right}
</Container>
</Container>
@@ -711,7 +721,9 @@ interface SmallLayoutProps {
const SmallLayout = (props: SmallLayoutProps) => {
return (
<div className="flex flex-center">
- <div className="flex-auto px3">{props.content}</div>
+ <Container className="flex-auto" paddingLeft={SIDE_PADDING} paddingRight={SIDE_PADDING}>
+ {props.content}
+ </Container>
</div>
);
}; // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
index b26bf512b..431cf145b 100644
--- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
@@ -9,6 +9,7 @@ import { Container } from 'ts/components/ui/container';
import { Image } from 'ts/components/ui/image';
import { Island } from 'ts/components/ui/island';
import { colors } from 'ts/style/colors';
+import { media } from 'ts/style/media';
import { styled } from 'ts/style/theme';
import { WebsiteBackendRelayerInfo } from 'ts/types';
import { utils } from 'ts/utils/utils';
@@ -55,7 +56,7 @@ const styles: Styles = {
};
const FALLBACK_IMG_SRC = '/images/relayer_fallback.png';
-const FALLBACK_PRIMARY_COLOR = colors.grey200;
+const FALLBACK_PRIMARY_COLOR = colors.grey300;
const NO_CONTENT_MESSAGE = '--';
const RELAYER_ICON_HEIGHT = '110px';
@@ -107,10 +108,14 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
const GridTile = styled(PlainGridTile)`
cursor: pointer;
- transition: transform 0.2s ease;
&:hover {
+ transition: transform 0.2s ease;
transform: translate(0px, -3px);
}
+ ${media.small`
+ transform: none !important;
+ transition: none !important;
+ `};
`;
interface SectionProps {
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
index 8743e4320..806eaeea5 100644
--- a/packages/website/ts/components/top_bar/provider_display.tsx
+++ b/packages/website/ts/components/top_bar/provider_display.tsx
@@ -1,23 +1,26 @@
import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
-import RaisedButton from 'material-ui/RaisedButton';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
-import Lock from 'material-ui/svg-icons/action/lock';
import * as React from 'react';
import { Blockchain } from 'ts/blockchain';
-import { ProviderPicker } from 'ts/components/top_bar/provider_picker';
import { AccountConnection } from 'ts/components/ui/account_connection';
import { Container } from 'ts/components/ui/container';
import { DropDown } from 'ts/components/ui/drop_down';
import { Identicon } from 'ts/components/ui/identicon';
+import { Image } from 'ts/components/ui/image';
import { Island } from 'ts/components/ui/island';
+import {
+ CopyAddressSimpleMenuItem,
+ DifferentWalletSimpleMenuItem,
+ GoToAccountManagementSimpleMenuItem,
+ SimpleMenu,
+} from 'ts/components/ui/simple_menu';
import { Text } from 'ts/components/ui/text';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { AccountState, ProviderType } from 'ts/types';
-import { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';
const ROOT_HEIGHT = 24;
@@ -44,11 +47,7 @@ const styles: Styles = {
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
public render(): React.ReactNode {
- const isExternallyInjectedProvider = utils.isExternallyInjected(
- this.props.providerType,
- this.props.injectedProviderName,
- );
- const hoverActiveNode = (
+ const activeNode = (
<Island className="flex items-center py1 px2" style={styles.root}>
{this._renderIcon()}
<Container marginLeft="12px" marginRight="12px">
@@ -57,93 +56,34 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
{this._renderInjectedProvider()}
</Island>
);
- const hasLedgerProvider = this.props.providerType === ProviderType.Ledger;
- const horizontalPosition = isExternallyInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
return (
<div style={{ width: 'fit-content', height: 48, float: 'right' }}>
<DropDown
- hoverActiveNode={hoverActiveNode}
- popoverContent={this.renderPopoverContent(isExternallyInjectedProvider, hasLedgerProvider)}
- anchorOrigin={{ horizontal: horizontalPosition, vertical: 'bottom' }}
- targetOrigin={{ horizontal: horizontalPosition, vertical: 'top' }}
+ activeNode={activeNode}
+ popoverContent={this._renderPopoverContent()}
+ anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
+ targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
zDepth={1}
/>
</div>
);
}
- public renderPopoverContent(hasInjectedProvider: boolean, hasLedgerProvider: boolean): React.ReactNode {
- if (!this._isBlockchainReady()) {
- return null;
- } else if (hasInjectedProvider || hasLedgerProvider) {
- return (
- <ProviderPicker
- dispatcher={this.props.dispatcher}
- networkId={this.props.networkId}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.props.onToggleLedgerDialog}
- blockchain={this.props.blockchain}
- />
- );
- } else {
- // Nothing to connect to, show install/info popover
- return (
- <div className="px2" style={{ maxWidth: 420 }}>
- <div className="center h4 py2" style={{ color: colors.grey700 }}>
- Choose a wallet:
- </div>
- <div className="flex pb3">
- <div className="center px2">
- <div style={{ color: colors.darkGrey }}>Install a browser wallet</div>
- <div className="py2">
- <img src="/images/metamask_or_parity.png" width="135" />
- </div>
- <div>
- Use{' '}
- <a
- href={constants.URL_METAMASK_CHROME_STORE}
- target="_blank"
- style={{ color: colors.lightBlueA700 }}
- >
- Metamask
- </a>{' '}
- or{' '}
- <a
- href={constants.URL_PARITY_CHROME_STORE}
- target="_blank"
- style={{ color: colors.lightBlueA700 }}
- >
- Parity Signer
- </a>
- </div>
- </div>
- <div>
- <div
- className="pl1 ml1"
- style={{ borderLeft: `1px solid ${colors.grey300}`, height: 65 }}
- />
- <div className="py1">or</div>
- <div
- className="pl1 ml1"
- style={{ borderLeft: `1px solid ${colors.grey300}`, height: 68 }}
- />
- </div>
- <div className="px2 center">
- <div style={{ color: colors.darkGrey }}>Connect to a ledger hardware wallet</div>
- <div style={{ paddingTop: 21, paddingBottom: 29 }}>
- <img src="/images/ledger_icon.png" style={{ width: 80 }} />
- </div>
- <div>
- <RaisedButton
- style={{ width: '100%' }}
- label="Use Ledger"
- onClick={this.props.onToggleLedgerDialog}
- />
- </div>
- </div>
- </div>
- </div>
- );
+ private _renderPopoverContent(): React.ReactNode {
+ const accountState = this._getAccountState();
+ switch (accountState) {
+ case AccountState.Ready:
+ return (
+ <SimpleMenu>
+ <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} />
+ <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} />
+ <GoToAccountManagementSimpleMenuItem />
+ </SimpleMenu>
+ );
+ case AccountState.Disconnected:
+ case AccountState.Locked:
+ case AccountState.Loading:
+ default:
+ return null;
}
}
private _renderIcon(): React.ReactNode {
@@ -154,7 +94,7 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
case AccountState.Loading:
return <CircularProgress size={ROOT_HEIGHT} thickness={2} />;
case AccountState.Locked:
- return <Lock color={colors.black} />;
+ return <Image src="/images/lock_icon.svg" height="20px" width="20px" />;
case AccountState.Disconnected:
return <ActionAccountBalanceWallet color={colors.mediumBlue} />;
default:
diff --git a/packages/website/ts/components/top_bar/provider_picker.tsx b/packages/website/ts/components/top_bar/provider_picker.tsx
deleted file mode 100644
index 7937f2e9d..000000000
--- a/packages/website/ts/components/top_bar/provider_picker.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { colors, constants as sharedConstants } from '@0xproject/react-shared';
-import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { ProviderType } from 'ts/types';
-
-interface ProviderPickerProps {
- networkId: number;
- injectedProviderName: string;
- providerType: ProviderType;
- onToggleLedgerDialog: () => void;
- dispatcher: Dispatcher;
- blockchain: Blockchain;
-}
-
-interface ProviderPickerState {}
-
-export class ProviderPicker extends React.Component<ProviderPickerProps, ProviderPickerState> {
- public render(): React.ReactNode {
- const isLedgerSelected = this.props.providerType === ProviderType.Ledger;
- const menuStyle = {
- padding: 10,
- paddingTop: 15,
- paddingBottom: 15,
- };
- // Show dropdown with two options
- return (
- <div style={{ width: 225, overflow: 'hidden' }}>
- <RadioButtonGroup name="provider" defaultSelected={this.props.providerType}>
- <RadioButton
- onClick={this._onProviderRadioChanged.bind(this, ProviderType.Injected)}
- style={{ ...menuStyle, backgroundColor: !isLedgerSelected && colors.grey50 }}
- value={ProviderType.Injected}
- label={this._renderLabel(this.props.injectedProviderName, !isLedgerSelected)}
- />
- <RadioButton
- onClick={this._onProviderRadioChanged.bind(this, ProviderType.Ledger)}
- style={{ ...menuStyle, backgroundColor: isLedgerSelected && colors.grey50 }}
- value={ProviderType.Ledger}
- label={this._renderLabel('Ledger Nano S', isLedgerSelected)}
- />
- </RadioButtonGroup>
- </div>
- );
- }
- private _renderLabel(title: string, shouldShowNetwork: boolean): React.ReactNode {
- const label = (
- <div className="flex">
- <div style={{ fontSize: 14 }}>{title}</div>
- {shouldShowNetwork && this._renderNetwork()}
- </div>
- );
- return label;
- }
- private _renderNetwork(): React.ReactNode {
- const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
- return (
- <div className="flex" style={{ marginTop: 1 }}>
- <div className="relative" style={{ width: 14, paddingLeft: 14 }}>
- <img
- src={`/images/network_icons/${networkName.toLowerCase()}.png`}
- className="absolute"
- style={{ top: 6, width: 10 }}
- />
- </div>
- <div style={{ color: colors.lightGrey, fontSize: 11 }}>{networkName}</div>
- </div>
- );
- }
- private _onProviderRadioChanged(value: string): void {
- if (value === ProviderType.Ledger) {
- this.props.onToggleLedgerDialog();
- } else {
- // tslint:disable-next-line:no-floating-promises
- this.props.blockchain.updateProviderToInjectedAsync();
- }
- }
-}
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index fac6c131f..960e5a824 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -11,6 +11,7 @@ import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu
import { DrawerMenu } from 'ts/components/portal/drawer_menu';
import { ProviderDisplay } from 'ts/components/top_bar/provider_display';
import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
+import { Container } from 'ts/components/ui/container';
import { DropDown } from 'ts/components/ui/drop_down';
import { Dispatcher } from 'ts/redux/dispatcher';
import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
@@ -45,6 +46,8 @@ export interface TopBarProps {
onVersionSelected?: (semver: string) => void;
sidebarHeader?: React.ReactNode;
maxWidth?: number;
+ paddingLeft?: number;
+ paddingRight?: number;
}
interface TopBarState {
@@ -67,13 +70,12 @@ const styles: Styles = {
color: colors.darkestGrey,
paddingTop: 6,
paddingBottom: 6,
- marginTop: 17,
cursor: 'pointer',
fontWeight: 400,
},
};
-const DEFAULT_HEIGHT = 59;
+const DEFAULT_HEIGHT = 68;
const EXPANDED_HEIGHT = 75;
export class TopBar extends React.Component<TopBarProps, TopBarState> {
@@ -81,6 +83,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
displayType: TopBarDisplayType.Default,
style: {},
isNightVersion: false,
+ paddingLeft: 20,
+ paddingRight: 20,
};
public static heightForDisplayType(displayType: TopBarDisplayType): number {
const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
@@ -102,7 +106,9 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
public render(): React.ReactNode {
const isNightVersion = this.props.isNightVersion;
const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded;
- const parentClassNames = `flex mx-auto ${isExpandedDisplayType ? 'pl3 py1' : 'max-width-4'}`;
+ const parentClassNames = !isExpandedDisplayType
+ ? 'flex mx-auto items-center max-width-4'
+ : 'flex mx-auto items-center';
const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
const developerSectionMenuItems = [
<Link key="subMenuItem-zeroEx" to={WebsitePaths.ZeroExJs} className="text-decoration-none">
@@ -197,9 +203,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
fontSize: 25,
color: isNightVersion ? 'white' : 'black',
cursor: 'pointer',
- paddingTop: 16,
};
- const hoverActiveNode = (
+ const activeNode = (
<div className="flex relative" style={{ color: menuIconStyle.color }}>
<div style={{ paddingRight: 10 }}>{this.props.translate.get(Key.Developers, Deco.Cap)}</div>
<div className="absolute" style={{ paddingLeft: 3, right: 3, top: -2 }}>
@@ -211,20 +216,26 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
// TODO : Remove this once we ship portal v2
const shouldShowPortalV2Drawer = this._isViewingPortal() && utils.shouldShowPortalV2();
return (
- <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }} className="pb1">
- <div className={parentClassNames} style={{ maxWidth: this.props.maxWidth }}>
- <div className="col col-2 sm-pl1 md-pl2 lg-pl0" style={{ paddingTop: 15 }}>
- <Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
- <img src={logoUrl} height="30" />
- </Link>
- </div>
- <div className={`col col-${isExpandedDisplayType ? '8' : '9'} lg-hide md-hide`} />
- <div className={`col col-${isExpandedDisplayType ? '6' : '5'} sm-hide xs-hide`} />
+ <div
+ style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }}
+ className="pb1 flex items-center"
+ >
+ <Container
+ className={parentClassNames}
+ width="100%"
+ maxWidth={this.props.maxWidth}
+ paddingLeft={this.props.paddingLeft}
+ paddingRight={this.props.paddingRight}
+ >
+ <Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
+ <img src={logoUrl} height="30" />
+ </Link>
+ <div className="flex-auto" />
{!this._isViewingPortal() && (
<div className={menuClasses}>
- <div className="flex justify-between">
+ <div className="flex items-center justify-between">
<DropDown
- hoverActiveNode={hoverActiveNode}
+ activeNode={activeNode}
popoverContent={popoverContent}
anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
@@ -252,7 +263,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
isExternal={false}
/>
<TopBarMenuItem
- title={this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
+ title={this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
path={`${WebsitePaths.Portal}`}
isPrimary={true}
style={styles.menuItem}
@@ -264,7 +275,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
)}
{this._isViewingPortal() && (
- <div className="sm-hide xs-hide col col-5" style={{ paddingTop: 8, marginRight: 36 }}>
+ <div className="sm-hide xs-hide">
<ProviderDisplay
dispatcher={this.props.dispatcher}
userAddress={this.props.userAddress}
@@ -277,12 +288,12 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
/>
</div>
)}
- <div className={`col ${isExpandedDisplayType ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
+ <div className={'md-hide lg-hide'}>
<div style={menuIconStyle}>
<i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
</div>
</div>
- </div>
+ </Container>
{shouldShowPortalV2Drawer ? this._renderPortalV2Drawer() : this._renderDrawer()}
</div>
);
diff --git a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
index 2e4254cfa..25fab2868 100644
--- a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
+++ b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
@@ -3,6 +3,8 @@ import * as _ from 'lodash';
import * as React from 'react';
import { Link } from 'react-router-dom';
+import { CallToAction } from 'ts/components/ui/button';
+
const DEFAULT_STYLE = {
color: colors.darkestGrey,
};
@@ -27,23 +29,15 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM
isNightVersion: false,
};
public render(): React.ReactNode {
- const primaryStyles = this.props.isPrimary
- ? {
- borderRadius: 4,
- border: `1px solid ${this.props.isNightVersion ? colors.grey : colors.greyishPink}`,
- marginTop: 15,
- paddingLeft: 9,
- paddingRight: 9,
- minWidth: 77,
- }
- : {};
const menuItemColor = this.props.isNightVersion ? 'white' : this.props.style.color;
const linkColor = _.isUndefined(menuItemColor) ? colors.darkestGrey : menuItemColor;
+ const itemContent = this.props.isPrimary ? (
+ <CallToAction padding="0.8em 1.5em">{this.props.title}</CallToAction>
+ ) : (
+ this.props.title
+ );
return (
- <div
- className={`center ${this.props.className}`}
- style={{ ...this.props.style, ...primaryStyles, color: menuItemColor }}
- >
+ <div className={`center ${this.props.className}`} style={{ ...this.props.style, color: menuItemColor }}>
{this.props.isExternal ? (
<a
className="text-decoration-none"
@@ -51,11 +45,11 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM
target="_blank"
href={this.props.path}
>
- {this.props.title}
+ {itemContent}
</a>
) : (
<Link to={this.props.path} className="text-decoration-none" style={{ color: linkColor }}>
- {this.props.title}
+ {itemContent}
</Link>
)}
</div>
diff --git a/packages/website/ts/components/ui/button.tsx b/packages/website/ts/components/ui/button.tsx
index 1489a74a6..2952c8859 100644
--- a/packages/website/ts/components/ui/button.tsx
+++ b/packages/website/ts/components/ui/button.tsx
@@ -11,6 +11,7 @@ export interface ButtonProps {
backgroundColor?: string;
borderColor?: string;
width?: string;
+ padding?: string;
type?: string;
isDisabled?: boolean;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
@@ -27,9 +28,8 @@ export const Button = styled(PlainButton)`
font-size: ${props => props.fontSize};
color: ${props => props.fontColor};
transition: background-color, opacity 0.5s ease;
- padding: 0.8em 2.2em;
+ padding: ${props => props.padding};
border-radius: 6px;
- box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
font-weight: 500;
outline: none;
font-family: ${props => props.fontFamily};
@@ -44,7 +44,6 @@ export const Button = styled(PlainButton)`
}
&:disabled {
opacity: 0.5;
- box-shadow: none;
}
&:focus {
background-color: ${props => saturate(0.2, props.backgroundColor)};
@@ -57,6 +56,7 @@ Button.defaultProps = {
width: 'auto',
fontFamily: 'Roboto',
isDisabled: false,
+ padding: '0.8em 2.2em',
};
Button.displayName = 'Button';
@@ -67,20 +67,26 @@ export interface CallToActionProps {
type?: CallToActionType;
fontSize?: string;
width?: string;
+ padding?: string;
}
-export const CallToAction: React.StatelessComponent<CallToActionProps> = ({ children, type, fontSize, width }) => {
+export const CallToAction: React.StatelessComponent<CallToActionProps> = ({
+ children,
+ type,
+ fontSize,
+ padding,
+ width,
+}) => {
const isLight = type === 'light';
- const backgroundColor = isLight ? colors.white : colors.heroGrey;
+ const backgroundColor = isLight ? colors.white : colors.mediumBlue;
const fontColor = isLight ? colors.heroGrey : colors.white;
- const borderColor = isLight ? undefined : colors.white;
return (
<Button
fontSize={fontSize}
+ padding={padding}
backgroundColor={backgroundColor}
fontColor={fontColor}
width={width}
- borderColor={borderColor}
>
{children}
</Button>
@@ -89,4 +95,5 @@ export const CallToAction: React.StatelessComponent<CallToActionProps> = ({ chil
CallToAction.defaultProps = {
type: 'dark',
+ fontSize: '14px',
};
diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx
index fb718d731..edbf8814b 100644
--- a/packages/website/ts/components/ui/container.tsx
+++ b/packages/website/ts/components/ui/container.tsx
@@ -17,6 +17,7 @@ export interface ContainerProps {
maxHeight?: StringOrNum;
width?: StringOrNum;
height?: StringOrNum;
+ minWidth?: StringOrNum;
minHeight?: StringOrNum;
isHidden?: boolean;
className?: string;
diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx
index 22cb942f8..4d5caef08 100644
--- a/packages/website/ts/components/ui/drop_down.tsx
+++ b/packages/website/ts/components/ui/drop_down.tsx
@@ -1,4 +1,4 @@
-import Popover, { PopoverAnimationVertical } from 'material-ui/Popover';
+import Popover from 'material-ui/Popover';
import * as React from 'react';
import { MaterialUIPosition } from 'ts/types';
@@ -7,13 +7,20 @@ const DEFAULT_STYLE = {
fontSize: 14,
};
-interface DropDownProps {
- hoverActiveNode: React.ReactNode;
+export enum DropdownMouseEvent {
+ Hover = 'hover',
+ Click = 'click',
+}
+
+export interface DropDownProps {
+ activeNode: React.ReactNode;
popoverContent: React.ReactNode;
anchorOrigin: MaterialUIPosition;
targetOrigin: MaterialUIPosition;
style?: React.CSSProperties;
zDepth?: number;
+ activateEvent?: DropdownMouseEvent;
+ closeEvent?: DropdownMouseEvent;
}
interface DropDownState {
@@ -25,6 +32,8 @@ export class DropDown extends React.Component<DropDownProps, DropDownState> {
public static defaultProps: Partial<DropDownProps> = {
style: DEFAULT_STYLE,
zDepth: 1,
+ activateEvent: DropdownMouseEvent.Hover,
+ closeEvent: DropdownMouseEvent.Hover,
};
private _isHovering: boolean;
private _popoverCloseCheckIntervalId: number;
@@ -58,46 +67,61 @@ export class DropDown extends React.Component<DropDownProps, DropDownState> {
onMouseEnter={this._onHover.bind(this)}
onMouseLeave={this._onHoverOff.bind(this)}
>
- {this.props.hoverActiveNode}
+ <div onClick={this._onActiveNodeClick.bind(this)}>{this.props.activeNode}</div>
<Popover
open={this.state.isDropDownOpen}
anchorEl={this.state.anchorEl}
anchorOrigin={this.props.anchorOrigin}
targetOrigin={this.props.targetOrigin}
onRequestClose={this._closePopover.bind(this)}
- useLayerForClickAway={false}
- animation={PopoverAnimationVertical}
+ useLayerForClickAway={this.props.closeEvent === DropdownMouseEvent.Click}
+ animated={false}
zDepth={this.props.zDepth}
>
- <div onMouseEnter={this._onHover.bind(this)} onMouseLeave={this._onHoverOff.bind(this)}>
+ <div
+ onMouseEnter={this._onHover.bind(this)}
+ onMouseLeave={this._onHoverOff.bind(this)}
+ onClick={this._closePopover.bind(this)}
+ >
{this.props.popoverContent}
</div>
</Popover>
</div>
);
}
+ private _onActiveNodeClick(event: React.FormEvent<HTMLInputElement>): void {
+ if (this.props.activateEvent === DropdownMouseEvent.Click) {
+ this.setState({
+ isDropDownOpen: true,
+ anchorEl: event.currentTarget,
+ });
+ }
+ }
private _onHover(event: React.FormEvent<HTMLInputElement>): void {
this._isHovering = true;
- this._checkIfShouldOpenPopover(event);
+ if (this.props.activateEvent === DropdownMouseEvent.Hover) {
+ this._checkIfShouldOpenPopover(event);
+ }
+ }
+ private _onHoverOff(): void {
+ this._isHovering = false;
}
private _checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>): void {
if (this.state.isDropDownOpen) {
return; // noop
}
-
this.setState({
isDropDownOpen: true,
anchorEl: event.currentTarget,
});
}
- private _onHoverOff(): void {
- this._isHovering = false;
- }
private _checkIfShouldClosePopover(): void {
- if (!this.state.isDropDownOpen || this._isHovering) {
+ if (!this.state.isDropDownOpen) {
return; // noop
}
- this._closePopover();
+ if (this.props.closeEvent === DropdownMouseEvent.Hover && !this._isHovering) {
+ this._closePopover();
+ }
}
private _closePopover(): void {
this.setState({
diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx
index 369dc8b7e..c4ff93531 100644
--- a/packages/website/ts/components/ui/image.tsx
+++ b/packages/website/ts/components/ui/image.tsx
@@ -6,6 +6,7 @@ export interface ImageProps {
src?: string;
fallbackSrc?: string;
height?: string | number;
+ borderRadius?: string;
width?: string | number;
}
interface ImageState {
@@ -26,6 +27,9 @@ export class Image extends React.Component<ImageProps, ImageState> {
className={this.props.className}
onError={this._onError.bind(this)}
src={src}
+ style={{
+ borderRadius: this.props.borderRadius,
+ }}
height={this.props.height}
width={this.props.width}
/>
diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx
new file mode 100644
index 000000000..74b8ef6ae
--- /dev/null
+++ b/packages/website/ts/components/ui/simple_menu.tsx
@@ -0,0 +1,88 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+import * as CopyToClipboard from 'react-copy-to-clipboard';
+import { Link } from 'react-router-dom';
+
+import { Container } from 'ts/components/ui/container';
+import { Text } from 'ts/components/ui/text';
+import { colors } from 'ts/style/colors';
+import { WebsitePaths } from 'ts/types';
+
+export interface SimpleMenuProps {
+ minWidth?: number | string;
+}
+
+export const SimpleMenu: React.StatelessComponent<SimpleMenuProps> = ({ children, minWidth }) => {
+ return (
+ <Container
+ marginLeft="16px"
+ marginRight="16px"
+ marginBottom="16px"
+ minWidth={minWidth}
+ className="flex flex-column"
+ >
+ {children}
+ </Container>
+ );
+};
+
+SimpleMenu.defaultProps = {
+ minWidth: '220px',
+};
+
+export interface SimpleMenuItemProps {
+ displayText: string;
+ onClick?: () => void;
+}
+export const SimpleMenuItem: React.StatelessComponent<SimpleMenuItemProps> = ({ displayText, onClick }) => {
+ // Falling back to _.noop for onclick retains the hovering effect
+ return (
+ <Container marginTop="16px" className="flex flex-column">
+ <Text
+ fontSize="14px"
+ fontColor={colors.darkGrey}
+ onClick={onClick || _.noop}
+ hoverColor={colors.mediumBlue}
+ >
+ {displayText}
+ </Text>
+ </Container>
+ );
+};
+
+export interface CopyAddressSimpleMenuItemProps {
+ userAddress: string;
+ onClick?: () => void;
+}
+export const CopyAddressSimpleMenuItem: React.StatelessComponent<CopyAddressSimpleMenuItemProps> = ({
+ userAddress,
+ onClick,
+}) => {
+ return (
+ <CopyToClipboard text={userAddress}>
+ <SimpleMenuItem displayText="Copy Address to Clipboard" onClick={onClick} />
+ </CopyToClipboard>
+ );
+};
+
+export interface GoToAccountManagementSimpleMenuItemProps {
+ onClick?: () => void;
+}
+export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent<
+ GoToAccountManagementSimpleMenuItemProps
+> = ({ onClick }) => {
+ return (
+ <Link to={`${WebsitePaths.Portal}/account`} style={{ textDecoration: 'none' }}>
+ <SimpleMenuItem displayText="Manage Account..." onClick={onClick} />
+ </Link>
+ );
+};
+
+export interface DifferentWalletSimpleMenuItemProps {
+ onClick?: () => void;
+}
+export const DifferentWalletSimpleMenuItem: React.StatelessComponent<DifferentWalletSimpleMenuItemProps> = ({
+ onClick,
+}) => {
+ return <SimpleMenuItem displayText="Use a Different Wallet..." onClick={onClick} />;
+};
diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx
index c1cb2ade4..315f72854 100644
--- a/packages/website/ts/components/ui/text.tsx
+++ b/packages/website/ts/components/ui/text.tsx
@@ -3,7 +3,7 @@ import { darken } from 'polished';
import * as React from 'react';
import { styled } from 'ts/style/theme';
-export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4';
+export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i';
export interface TextProps {
className?: string;
@@ -17,6 +17,7 @@ export interface TextProps {
fontWeight?: number | string;
textDecorationLine?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
+ hoverColor?: string;
}
const PlainText: React.StatelessComponent<TextProps> = ({ children, className, onClick, Tag }) => (
@@ -37,7 +38,7 @@ export const Text = styled(PlainText)`
${props => (props.onClick ? 'cursor: pointer' : '')};
transition: color 0.5s ease;
&:hover {
- ${props => (props.onClick ? `color: ${darken(0.3, props.fontColor)}` : '')};
+ ${props => (props.onClick ? `color: ${props.hoverColor || darken(0.3, props.fontColor)}` : '')};
}
`;
diff --git a/packages/website/ts/components/wallet/body_overlay.tsx b/packages/website/ts/components/wallet/body_overlay.tsx
index 5ced704f9..26359d0d2 100644
--- a/packages/website/ts/components/wallet/body_overlay.tsx
+++ b/packages/website/ts/components/wallet/body_overlay.tsx
@@ -9,11 +9,11 @@ import { Text } from 'ts/components/ui/text';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { styled } from 'ts/style/theme';
-import { AccountState, BrowserType, ProviderType } from 'ts/types';
-import { constants } from 'ts/utils/constants';
+import { AccountState, ProviderType } from 'ts/types';
import { utils } from 'ts/utils/utils';
const METAMASK_IMG_SRC = '/images/metamask_icon.png';
+const TOSHI_IMG_SRC = '/images/toshi_logo.jpg';
export interface BodyOverlayProps {
dispatcher: Dispatcher;
@@ -92,8 +92,10 @@ interface DisconnectedOverlayProps {
const DisconnectedOverlay = (props: DisconnectedOverlayProps) => {
return (
<div className="flex flex-column items-center">
- <GetMetaMask />
- <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} />
+ <GetWalletCallToAction />
+ {!utils.isMobileOperatingSystem() && (
+ <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} />
+ )}
</div>
);
};
@@ -112,32 +114,20 @@ const UseDifferentWallet = (props: UseDifferentWallet) => {
);
};
-const GetMetaMask = () => {
- const browserType = utils.getBrowserType();
- let extensionLink;
- switch (browserType) {
- case BrowserType.Chrome:
- extensionLink = constants.URL_METAMASK_CHROME_STORE;
- break;
- case BrowserType.Firefox:
- extensionLink = constants.URL_METAMASK_FIREFOX_STORE;
- break;
- case BrowserType.Opera:
- extensionLink = constants.URL_METAMASK_OPERA_STORE;
- break;
- default:
- extensionLink = constants.URL_METAMASK_HOMEPAGE;
- }
+const GetWalletCallToAction = () => {
+ const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile();
+ const imageUrl = isOnMobile ? TOSHI_IMG_SRC : METAMASK_IMG_SRC;
+ const text = isOnMobile ? 'Get Toshi Wallet' : 'Get MetaMask Wallet';
return (
- <a href={extensionLink} target="_blank" style={{ textDecoration: 'none' }}>
+ <a href={downloadLink} target="_blank" style={{ textDecoration: 'none' }}>
<Island
className="flex items-center py1 px2"
style={{ height: 28, borderRadius: 28, backgroundColor: colors.mediumBlue }}
>
- <Image src={METAMASK_IMG_SRC} width="28px" />
+ <Image src={imageUrl} width="28px" borderRadius="22%" />
<Container marginLeft="8px" marginRight="12px">
<Text fontColor={colors.white} fontSize="16px" fontWeight={500}>
- Get MetaMask Wallet
+ {text}
</Text>
</Container>
</Island>
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 1f1e3598a..de3b91ad0 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -1,19 +1,25 @@
import { constants as sharedConstants, EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
import { BigNumber, errorUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import firstBy = require('thenby');
import { Blockchain } from 'ts/blockchain';
import { AccountConnection } from 'ts/components/ui/account_connection';
import { Container } from 'ts/components/ui/container';
+import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down';
import { IconButton } from 'ts/components/ui/icon_button';
import { Identicon } from 'ts/components/ui/identicon';
import { Island } from 'ts/components/ui/island';
+import {
+ CopyAddressSimpleMenuItem,
+ DifferentWalletSimpleMenuItem,
+ GoToAccountManagementSimpleMenuItem,
+ SimpleMenu,
+ SimpleMenuItem,
+} from 'ts/components/ui/simple_menu';
import { Text } from 'ts/components/ui/text';
import { TokenIcon } from 'ts/components/ui/token_icon';
import { BodyOverlay } from 'ts/components/wallet/body_overlay';
@@ -34,7 +40,6 @@ import {
TokenByAddress,
TokenState,
TokenStateByAddress,
- WebsitePaths,
} from 'ts/types';
import { analytics } from 'ts/utils/analytics';
import { constants } from 'ts/utils/constants';
@@ -83,9 +88,7 @@ const ICON_DIMENSION = 28;
const BODY_ITEM_KEY = 'BODY';
const HEADER_ITEM_KEY = 'HEADER';
const ETHER_ITEM_KEY = 'ETHER';
-const USD_DECIMAL_PLACES = 2;
const NO_ALLOWANCE_TOGGLE_SPACE_WIDTH = 56;
-const ACCOUNT_PATH = `${WebsitePaths.Portal}/account`;
const PLACEHOLDER_COLOR = colors.grey300;
const LOADING_ROWS_COUNT = 6;
@@ -189,6 +192,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
);
}
private _renderConnectedHeaderRows(): React.ReactElement<{}> {
+ const isMobile = this.props.screenWidth === ScreenWidths.Sm;
const userAddress = this.props.userAddress;
const accountState = this._getAccountState();
const main = (
@@ -199,15 +203,49 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
<AccountConnection accountState={accountState} injectedProviderName={this.props.injectedProviderName} />
</div>
);
+ const onClick = _.noop;
+ const accessory = (
+ <DropDown
+ activeNode={
+ // this container gives the menu button more of a hover target for the drop down
+ // it prevents accidentally closing the menu by moving off of the button
+ <Container paddingLeft="100px" paddingRight="15px">
+ <Text
+ className="zmdi zmdi-more-horiz"
+ Tag="i"
+ fontSize="32px"
+ fontFamily="Material-Design-Iconic-Font"
+ fontColor={colors.darkGrey}
+ onClick={onClick}
+ hoverColor={colors.mediumBlue}
+ />
+ </Container>
+ }
+ popoverContent={
+ <SimpleMenu minWidth="150px">
+ <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} />
+ {!isMobile && <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} />}
+ <SimpleMenuItem displayText="Add Tokens..." onClick={this.props.onAddToken} />
+ <SimpleMenuItem displayText="Remove Tokens..." onClick={this.props.onRemoveToken} />
+ {!isMobile && <GoToAccountManagementSimpleMenuItem />}
+ </SimpleMenu>
+ }
+ anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
+ targetOrigin={{ horizontal: 'right', vertical: 'top' }}
+ zDepth={1}
+ activateEvent={DropdownMouseEvent.Click}
+ closeEvent={DropdownMouseEvent.Click}
+ />
+ );
return (
- <Link key={HEADER_ITEM_KEY} to={ACCOUNT_PATH} style={{ textDecoration: 'none' }}>
- <StandardIconRow
- icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
- main={main}
- minHeight="60px"
- backgroundColor={colors.white}
- />
- </Link>
+ <StandardIconRow
+ key={HEADER_ITEM_KEY}
+ icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
+ main={main}
+ accessory={accessory}
+ minHeight="60px"
+ backgroundColor={colors.white}
+ />
);
}
private _renderBody(): React.ReactElement<{}> {
@@ -320,8 +358,24 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection &&
!_.isUndefined(this.props.userEtherBalanceInWei);
const etherToken = this._getEthToken();
+ const wrapEtherItem = shouldShowWrapEtherItem ? (
+ <WrapEtherItem
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ blockchain={this.props.blockchain}
+ dispatcher={this.props.dispatcher}
+ userEtherBalanceInWei={this.props.userEtherBalanceInWei}
+ direction={accessoryItemConfig.wrappedEtherDirection}
+ etherToken={etherToken}
+ lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
+ onConversionSuccessful={this._closeWrappedEtherActionRow.bind(this)}
+ // tslint:disable:jsx-no-lambda
+ refetchEthTokenStateAsync={async () => this.props.refetchTokenStateAsync(etherToken.address)}
+ />
+ ) : null;
return (
<div id={key} key={key} className={`flex flex-column ${className || ''}`}>
+ {this.state.wrappedEtherDirection === Side.Receive && wrapEtherItem}
<StandardIconRow
icon={icon}
main={
@@ -331,23 +385,8 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
</div>
}
accessory={this._renderAccessoryItems(accessoryItemConfig)}
- backgroundColor={shouldShowWrapEtherItem ? colors.walletFocusedItemBackground : undefined}
/>
- {shouldShowWrapEtherItem && (
- <WrapEtherItem
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- direction={accessoryItemConfig.wrappedEtherDirection}
- etherToken={etherToken}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- onConversionSuccessful={this._closeWrappedEtherActionRow.bind(this)}
- // tslint:disable:jsx-no-lambda
- refetchEthTokenStateAsync={async () => this.props.refetchTokenStateAsync(etherToken.address)}
- />
- )}
+ {this.state.wrappedEtherDirection === Side.Deposit && wrapEtherItem}
</div>
);
}
@@ -411,19 +450,11 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
price?: BigNumber,
isLoading: boolean = false,
): React.ReactNode {
- let result;
- if (!isLoading) {
- if (_.isUndefined(price)) {
- result = '--';
- } else {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const value = unitAmount.mul(price);
- const formattedAmount = value.toFixed(USD_DECIMAL_PLACES);
- result = `$${formattedAmount}`;
- }
- } else {
- result = '$0.00';
- }
+ const result = !isLoading
+ ? _.isUndefined(price)
+ ? '--'
+ : utils.getUsdValueFormattedAmount(amount, decimals, price)
+ : '$0.00';
return (
<PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}>
<Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em">
diff --git a/packages/website/ts/components/wallet/wrap_ether_item.tsx b/packages/website/ts/components/wallet/wrap_ether_item.tsx
index 851b35f90..2b4cf93fe 100644
--- a/packages/website/ts/components/wallet/wrap_ether_item.tsx
+++ b/packages/website/ts/components/wallet/wrap_ether_item.tsx
@@ -8,6 +8,7 @@ import * as React from 'react';
import { Blockchain } from 'ts/blockchain';
import { EthAmountInput } from 'ts/components/inputs/eth_amount_input';
import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
+import { Container } from 'ts/components/ui/container';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { BlockchainCallErrs, Side, Token } from 'ts/types';
@@ -94,7 +95,7 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
const topLabelText = isWrappingEth ? 'Convert ETH into WETH 1:1' : 'Convert WETH into ETH 1:1';
return (
- <div className="flex" style={{ backgroundColor: colors.walletFocusedItemBackground }}>
+ <Container className="flex" backgroundColor={colors.walletFocusedItemBackground} paddingTop="25px">
<div>{this._renderIsEthConversionHappeningSpinner()} </div>
<div className="flex flex-column">
<div style={styles.topLabel}>{topLabelText}</div>
@@ -142,7 +143,7 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
{this._renderErrorMsg()}
</div>
- </div>
+ </Container>
);
}
private _onValueChange(_isValid: boolean, amount?: BigNumber): void {
diff --git a/packages/website/ts/containers/subproviders_documentation.ts b/packages/website/ts/containers/subproviders_documentation.ts
index 6d4230e53..567f6a37e 100644
--- a/packages/website/ts/containers/subproviders_documentation.ts
+++ b/packages/website/ts/containers/subproviders_documentation.ts
@@ -25,6 +25,7 @@ const docSections = {
emptyWalletSubprovider: 'emptyWalletSubprovider',
fakeGasEstimateSubprovider: 'fakeGasEstimateSubprovider',
injectedWeb3Subprovider: 'injectedWeb3Subprovider',
+ signerSubprovider: 'signerSubprovider',
redundantRPCSubprovider: 'redundantRPCSubprovider',
ganacheSubprovider: 'ganacheSubprovider',
nonceTrackerSubprovider: 'nonceTrackerSubprovider',
@@ -50,6 +51,7 @@ const docsInfoConfig: DocsInfoConfig = {
['emptyWallet-subprovider']: [docSections.emptyWalletSubprovider],
['fakeGasEstimate-subprovider']: [docSections.fakeGasEstimateSubprovider],
['injectedWeb3-subprovider']: [docSections.injectedWeb3Subprovider],
+ ['signer-subprovider']: [docSections.signerSubprovider],
['redundantRPC-subprovider']: [docSections.redundantRPCSubprovider],
['ganache-subprovider']: [docSections.ganacheSubprovider],
['nonceTracker-subprovider']: [docSections.nonceTrackerSubprovider],
@@ -69,6 +71,7 @@ const docsInfoConfig: DocsInfoConfig = {
[docSections.emptyWalletSubprovider]: ['"subproviders/src/subproviders/empty_wallet_subprovider"'],
[docSections.fakeGasEstimateSubprovider]: ['"subproviders/src/subproviders/fake_gas_estimate_subprovider"'],
[docSections.injectedWeb3Subprovider]: ['"subproviders/src/subproviders/injected_web3"'],
+ [docSections.signerSubprovider]: ['"subproviders/src/subproviders/signer"'],
[docSections.redundantRPCSubprovider]: ['"subproviders/src/subproviders/redundant_rpc"'],
[docSections.ganacheSubprovider]: ['"subproviders/src/subproviders/ganache"'],
[docSections.nonceTrackerSubprovider]: ['"subproviders/src/subproviders/nonce_tracker"'],
diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx
index 0259af36f..5bb5d06a9 100644
--- a/packages/website/ts/pages/about/about.tsx
+++ b/packages/website/ts/pages/about/about.tsx
@@ -165,16 +165,24 @@ const teamRow5: ProfileInfo[] = [
},
];
-// const teamRow6: ProfileInfo[] = [
-// {
-// name: 'Chris Kalani',
-// title: 'Director of Design',
-// description: `Previously founded Wake (acquired by InVision). Early Facebook product designer.`,
-// image: 'images/team/chris.png',
-// linkedIn: 'https://www.linkedin.com/in/chriskalani/',
-// github: 'https://github.com/chriskalani',
-// },
-// ];
+const teamRow6: ProfileInfo[] = [
+ {
+ name: 'Alex Browne',
+ title: 'Engineer in Residence',
+ description: `Full-stack blockchain engineer. Previously at Plaid. Open source guru and footgun dismantler. Computer Science and Electrical Engineering at Duke.`,
+ image: 'images/team/alexbrowne.png',
+ linkedIn: 'https://www.linkedin.com/in/stephenalexbrowne/',
+ github: 'http://github.com/albrow',
+ },
+ // {
+ // name: 'Chris Kalani',
+ // title: 'Director of Design',
+ // description: `Previously founded Wake (acquired by InVision). Early Facebook product designer.`,
+ // image: 'images/team/chris.png',
+ // linkedIn: 'https://www.linkedin.com/in/chriskalani/',
+ // github: 'https://github.com/chriskalani',
+ // },
+];
const advisors: ProfileInfo[] = [
{
@@ -270,6 +278,7 @@ export class About extends React.Component<AboutProps, AboutState> {
<div className="clearfix">{this._renderProfiles(teamRow3)}</div>
<div className="clearfix">{this._renderProfiles(teamRow4)}</div>
<div className="clearfix">{this._renderProfiles(teamRow5)}</div>
+ <div className="clearfix">{this._renderProfiles(teamRow6)}</div>
</div>
<div className="pt3 pb2">
<div
diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
index f091778f4..b2cf4d979 100644
--- a/packages/website/ts/pages/landing/landing.tsx
+++ b/packages/website/ts/pages/landing/landing.tsx
@@ -268,15 +268,11 @@ export class Landing extends React.Component<LandingProps, LandingState> {
</Link>
</div>
<div className="lg-col lg-col-6 sm-center sm-col sm-col-12">
- <a
- href={constants.URL_ZEROEX_CHAT}
- target="_blank"
- className="text-decoration-none"
- >
+ <Link to={WebsitePaths.Portal} className="text-decoration-none">
<CallToAction width="175px">
- {this.props.translate.get(Key.CommunityCallToAction, Deco.Cap)}
+ {this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
</CallToAction>
- </a>
+ </Link>
</div>
</Container>
</div>
@@ -295,7 +291,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
<div
className="mr1 px1"
style={{
- backgroundColor: colors.lightTurquois,
+ backgroundColor: colors.white,
borderRadius: 3,
color: colors.heroGrey,
height: 23,
diff --git a/packages/website/ts/redux/store.ts b/packages/website/ts/redux/store.ts
index 0d0e6cea1..2672e3f61 100644
--- a/packages/website/ts/redux/store.ts
+++ b/packages/website/ts/redux/store.ts
@@ -13,9 +13,11 @@ export const store: ReduxStore<State> = createStore(
);
store.subscribe(
_.throttle(() => {
+ const state = store.getState();
// Persisted state
stateStorage.saveState({
- hasPortalOnboardingBeenClosed: store.getState().hasPortalOnboardingBeenClosed,
+ hasPortalOnboardingBeenClosed: state.hasPortalOnboardingBeenClosed,
+ isPortalOnboardingShowing: state.isPortalOnboardingShowing,
});
}, ONE_SECOND),
);
diff --git a/packages/website/ts/style/media.ts b/packages/website/ts/style/media.ts
new file mode 100644
index 000000000..870d9a277
--- /dev/null
+++ b/packages/website/ts/style/media.ts
@@ -0,0 +1,14 @@
+import { css } from 'ts/style/theme';
+import { ScreenWidths } from 'ts/types';
+
+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),
+};
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 498a0a5b8..f7324e87a 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -1,5 +1,6 @@
import { ECSignature } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
+import { Provider } from 'ethereum-types';
import * as React from 'react';
export enum Side {
@@ -215,10 +216,11 @@ export interface ContractEvent {
}
export type ValidatedBigNumberCallback = (isValid: boolean, amount?: BigNumber) => void;
+// Associated values are in `em` units
export enum ScreenWidths {
- Sm = 'SM',
- Md = 'MD',
- Lg = 'LG',
+ Sm = 40,
+ Md = 52,
+ Lg = 64,
}
export enum AlertTypes {
@@ -454,6 +456,7 @@ export enum Key {
Developers = 'DEVELOPERS',
Home = 'HOME',
RocketChat = 'ROCKETCHAT',
+ TradeCallToAction = 'TRADE_CALL_TO_ACTION',
}
export enum SmartContractDocSections {
@@ -487,6 +490,8 @@ export enum Providers {
Parity = 'PARITY',
Metamask = 'METAMASK',
Mist = 'MIST',
+ Toshi = 'TOSHI',
+ Cipher = 'CIPHER',
}
export interface InjectedProviderUpdate {
@@ -565,10 +570,32 @@ export enum BrowserType {
Other = 'Other',
}
+export enum OperatingSystemType {
+ Android = 'Android',
+ iOS = 'iOS',
+ Mac = 'Mac',
+ Windows = 'Windows',
+ WindowsPhone = 'WindowsPhone',
+ Linux = 'Linux',
+ Other = 'Other',
+}
+
export enum AccountState {
Disconnected = 'Disconnected',
Ready = 'Ready',
Loading = 'Loading',
Locked = 'Locked',
}
+
+export interface InjectedProvider extends Provider {
+ publicConfigStore?: InjectedProviderObservable;
+}
+
+// Minimal expected interface for an injected web3 object
+export interface InjectedWeb3 {
+ currentProvider: InjectedProvider;
+ version: {
+ getNetwork(cd: (err: Error, networkId: string) => void): void;
+ };
+}
// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/utils/analytics.ts b/packages/website/ts/utils/analytics.ts
index 928e45bc3..f4bfa083f 100644
--- a/packages/website/ts/utils/analytics.ts
+++ b/packages/website/ts/utils/analytics.ts
@@ -1,8 +1,8 @@
import * as _ from 'lodash';
import * as ReactGA from 'react-ga';
+import { InjectedWeb3 } from 'ts/types';
import { configs } from 'ts/utils/configs';
import { utils } from 'ts/utils/utils';
-import * as Web3 from 'web3';
export const analytics = {
init(): void {
@@ -16,11 +16,12 @@ export const analytics = {
value,
});
},
- async logProviderAsync(web3IfExists: Web3): Promise<void> {
+ async logProviderAsync(web3IfExists: InjectedWeb3): Promise<void> {
await utils.onPageLoadAsync();
- const providerType = !_.isUndefined(web3IfExists)
- ? utils.getProviderType(web3IfExists.currentProvider)
- : 'NONE';
+ const providerType =
+ !_.isUndefined(web3IfExists) && !_.isUndefined(web3IfExists.currentProvider)
+ ? utils.getProviderType(web3IfExists.currentProvider)
+ : 'NONE';
ReactGA.ga('set', 'dimension1', providerType);
},
};
diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts
index d3a2aa107..4b3443d21 100644
--- a/packages/website/ts/utils/constants.ts
+++ b/packages/website/ts/utils/constants.ts
@@ -6,7 +6,7 @@ export const constants = {
ETHER_TOKEN_SYMBOL: 'WETH',
ZRX_TOKEN_SYMBOL: 'ZRX',
ETHER_SYMBOL: 'ETH',
- TOKEN_AMOUNT_DISPLAY_PRECISION: 5,
+ TOKEN_AMOUNT_DISPLAY_PRECISION: 4,
GENESIS_ORDER_BLOCK_BY_NETWORK_ID: {
1: 4145578,
42: 3117574,
@@ -29,6 +29,8 @@ export const constants = {
PROVIDER_NAME_METAMASK: 'MetaMask',
PROVIDER_NAME_PARITY_SIGNER: 'Parity Signer',
PROVIDER_NAME_MIST: 'Mist',
+ PROVIDER_NAME_CIPHER: 'Cipher Browser',
+ PROVIDER_NAME_TOSHI: 'Toshi',
PROVIDER_NAME_GENERIC: 'Injected Web3',
PROVIDER_NAME_PUBLIC: '0x Public',
ROLLBAR_ACCESS_TOKEN: 'a6619002b51c4464928201e6ea94de65',
@@ -38,6 +40,7 @@ export const constants = {
UNAVAILABLE_STATUS: 503,
TAKER_FEE: new BigNumber(0),
TESTNET_NAME: 'Kovan',
+ NUMERAL_USD_FORMAT: '$0,0.00',
PROJECT_URL_ETHFINEX: 'https://www.ethfinex.com/',
PROJECT_URL_AMADEUS: 'http://amadeusrelay.org',
PROJECT_URL_DDEX: 'https://ddex.io',
@@ -71,6 +74,8 @@ export const constants = {
URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki',
URL_METAMASK_CHROME_STORE: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
URL_METAMASK_FIREFOX_STORE: 'https://addons.mozilla.org/en-US/firefox/addon/ether-metamask/',
+ URL_TOSHI_IOS_APP_STORE: 'https://itunes.apple.com/us/app/toshi-ethereum-wallet/id1278383455?mt=8',
+ URL_TOSHI_ANDROID_APP_STORE: 'https://play.google.com/store/apps/details?id=org.toshi&hl=en_US',
URL_METAMASK_HOMEPAGE: 'https://metamask.io/',
URL_METAMASK_OPERA_STORE: 'https://addons.opera.com/en/extensions/details/metamask/',
URL_MIST_DOWNLOAD: 'https://github.com/ethereum/mist/releases',
diff --git a/packages/website/ts/utils/translate.ts b/packages/website/ts/utils/translate.ts
index 39924b6f7..1ee1a59c5 100644
--- a/packages/website/ts/utils/translate.ts
+++ b/packages/website/ts/utils/translate.ts
@@ -55,6 +55,19 @@ export class Translate {
}
public get(key: Key, decoration?: Deco): string {
let text = this._translation[key];
+ // if a translation does not exist for a certain language, fallback to english
+ // if it still doesn't exist in english, throw an error
+ if (_.isUndefined(text)) {
+ const englishTranslation: Translation = languageToTranslations[Language.English];
+ const englishText = englishTranslation[key];
+ if (!_.isUndefined(englishText)) {
+ text = englishText;
+ } else {
+ throw new Error(
+ `Translation key not available in ${this._selectedLanguage} or ${Language.English}: ${key}`,
+ );
+ }
+ }
if (!_.isUndefined(decoration) && !_.includes(languagesWithoutCaps, this._selectedLanguage)) {
switch (decoration) {
case Deco.Cap:
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
index 726e1815f..623819fc9 100644
--- a/packages/website/ts/utils/utils.ts
+++ b/packages/website/ts/utils/utils.ts
@@ -8,11 +8,14 @@ import * as bowser from 'bowser';
import deepEqual = require('deep-equal');
import * as _ from 'lodash';
import * as moment from 'moment';
+import * as numeral from 'numeral';
+
import {
AccountState,
BlockchainCallErrs,
BrowserType,
Environments,
+ OperatingSystemType,
Order,
Providers,
ProviderType,
@@ -27,9 +30,6 @@ import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import * as u2f from 'ts/vendor/u2f_api';
-const LG_MIN_EM = 64;
-const MD_MIN_EM = 52;
-
const isDogfood = (): boolean => _.includes(window.location.href, configs.DOMAIN_DOGFOOD);
export const utils = {
@@ -134,9 +134,9 @@ export const utils = {
// This logic mirrors the CSS media queries in BassCSS for the `lg-`, `md-` and `sm-` CSS
// class prefixes. Do not edit these.
- if (widthInEm > LG_MIN_EM) {
+ if (widthInEm > ScreenWidths.Lg) {
return ScreenWidths.Lg;
- } else if (widthInEm > MD_MIN_EM) {
+ } else if (widthInEm > ScreenWidths.Md) {
return ScreenWidths.Md;
} else {
return ScreenWidths.Sm;
@@ -324,6 +324,7 @@ export const utils = {
getProviderType(provider: Provider): Providers | string {
const constructorName = provider.constructor.name;
let parsedProviderName = constructorName;
+ // https://ethereum.stackexchange.com/questions/24266/elegant-way-to-detect-current-provider-int-web3-js
switch (constructorName) {
case 'EthereumProvider':
parsedProviderName = Providers.Mist;
@@ -337,6 +338,10 @@ export const utils = {
parsedProviderName = Providers.Parity;
} else if ((provider as any).isMetaMask) {
parsedProviderName = Providers.Metamask;
+ } else if (!_.isUndefined(_.get(window, 'SOFA'))) {
+ parsedProviderName = Providers.Toshi;
+ } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) {
+ parsedProviderName = Providers.Cipher;
}
return parsedProviderName;
},
@@ -380,16 +385,29 @@ export const utils = {
},
getFormattedAmount(amount: BigNumber, decimals: number, symbol: string): string {
const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const precision = Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces());
- const formattedAmount = unitAmount.toFixed(precision);
+ // if the unit amount is less than 1, show the natural number of decimal places with a max of 4
+ // if the unit amount is greater than or equal to 1, show only 2 decimal places
+ const precision = unitAmount.lt(1)
+ ? Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces())
+ : 2;
+ const format = `0,0.${_.repeat('0', precision)}`;
+ const formattedAmount = numeral(unitAmount).format(format);
return `${formattedAmount} ${symbol}`;
},
+ getUsdValueFormattedAmount(amount: BigNumber, decimals: number, price: BigNumber): string {
+ const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
+ const value = unitAmount.mul(price);
+ return numeral(value).format(constants.NUMERAL_USD_FORMAT);
+ },
openUrl(url: string): void {
window.open(url, '_blank');
},
- isMobile(screenWidth: ScreenWidths): boolean {
+ isMobileWidth(screenWidth: ScreenWidths): boolean {
return screenWidth === ScreenWidths.Sm;
},
+ isMobileOperatingSystem(): boolean {
+ return bowser.mobile;
+ },
getBrowserType(): BrowserType {
if (bowser.chrome) {
return BrowserType.Chrome;
@@ -401,7 +419,59 @@ export const utils = {
return BrowserType.Other;
}
},
+ getOperatingSystem(): OperatingSystemType {
+ if (bowser.android) {
+ return OperatingSystemType.Android;
+ } else if (bowser.ios) {
+ return OperatingSystemType.iOS;
+ } else if (bowser.mac) {
+ return OperatingSystemType.Mac;
+ } else if (bowser.windows) {
+ return OperatingSystemType.Windows;
+ } else if (bowser.windowsphone) {
+ return OperatingSystemType.WindowsPhone;
+ } else if (bowser.linux) {
+ return OperatingSystemType.Linux;
+ } else {
+ return OperatingSystemType.Other;
+ }
+ },
isTokenTracked(token: Token): boolean {
return !_.isUndefined(token.trackedTimestamp);
},
+ // Returns a [downloadLink, isOnMobile] tuple.
+ getBestWalletDownloadLinkAndIsMobile(): [string, boolean] {
+ const browserType = utils.getBrowserType();
+ const isOnMobile = utils.isMobileOperatingSystem();
+ const operatingSystem = utils.getOperatingSystem();
+ let downloadLink;
+ if (isOnMobile) {
+ switch (operatingSystem) {
+ case OperatingSystemType.Android:
+ downloadLink = constants.URL_TOSHI_ANDROID_APP_STORE;
+ break;
+ case OperatingSystemType.iOS:
+ downloadLink = constants.URL_TOSHI_IOS_APP_STORE;
+ break;
+ default:
+ // Toshi is only supported on these mobile OSes - just default to iOS
+ downloadLink = constants.URL_TOSHI_IOS_APP_STORE;
+ }
+ } else {
+ switch (browserType) {
+ case BrowserType.Chrome:
+ downloadLink = constants.URL_METAMASK_CHROME_STORE;
+ break;
+ case BrowserType.Firefox:
+ downloadLink = constants.URL_METAMASK_FIREFOX_STORE;
+ break;
+ case BrowserType.Opera:
+ downloadLink = constants.URL_METAMASK_OPERA_STORE;
+ break;
+ default:
+ downloadLink = constants.URL_METAMASK_HOMEPAGE;
+ }
+ }
+ return [downloadLink, isOnMobile];
+ },
};
diff --git a/yarn.lock b/yarn.lock
index fae380f11..aebbdacaf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -330,7 +330,7 @@
"@types/mocha@^5.2.2":
version "5.2.3"
- resolved "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.3.tgz#11f3a5629d67cd444fa6c94536576244e6a52ea9"
+ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.3.tgz#11f3a5629d67cd444fa6c94536576244e6a52ea9"
"@types/nock@^9.1.2":
version "9.1.3"
@@ -350,6 +350,10 @@
version "8.10.8"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.8.tgz#794cba23cc9f8d9715f6543fa8827433b5f5cd3b"
+"@types/numeral@^0.0.22":
+ version "0.0.22"
+ resolved "https://registry.yarnpkg.com/@types/numeral/-/numeral-0.0.22.tgz#86bef1f0a2d743afdc2ef3168d45f2905e1a0b93"
+
"@types/opn@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/opn/-/opn-5.1.0.tgz#bff7bc371677f4bdbb37884400e03fd81f743927"
@@ -553,6 +557,16 @@ acorn-dynamic-import@^2.0.0:
dependencies:
acorn "^4.0.3"
+acorn-jsx@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+ dependencies:
+ acorn "^3.0.4"
+
+acorn@^3.0.4:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+
acorn@^4.0.3:
version "4.0.13"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
@@ -561,6 +575,10 @@ acorn@^5.0.0:
version "5.5.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9"
+acorn@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
+
add-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
@@ -573,6 +591,10 @@ aes-js@^0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d"
+ajv-keywords@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
+
ajv-keywords@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be"
@@ -584,7 +606,7 @@ ajv@^4.9.1:
co "^4.6.0"
json-stable-stringify "^1.0.1"
-ajv@^5.1.0:
+ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
@@ -672,6 +694,10 @@ ansi-wrap@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
+antlr4@4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.0.tgz#297f956ddc06f83397fc0990ecf2e0cf20bfbbee"
+
any-observable@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242"
@@ -1604,6 +1630,12 @@ base-x@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-1.1.0.tgz#42d3d717474f9ea02207f6d1aa1f426913eeb7ac"
+base-x@^3.0.2:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.4.tgz#94c1788736da065edb1d68808869e357c977fa77"
+ dependencies:
+ safe-buffer "^5.0.1"
+
base64-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
@@ -1756,6 +1788,24 @@ bip66@^1.1.3:
dependencies:
safe-buffer "^5.0.1"
+bitcore-lib@^0.15.0:
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/bitcore-lib/-/bitcore-lib-0.15.0.tgz#f924be13869f2aab7e04aeec5642ad3359b6cec2"
+ dependencies:
+ bn.js "=4.11.8"
+ bs58 "=4.0.1"
+ buffer-compare "=1.1.1"
+ elliptic "=6.4.0"
+ inherits "=2.0.1"
+ lodash "=4.17.4"
+
+bitcore-mnemonic@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/bitcore-mnemonic/-/bitcore-mnemonic-1.5.0.tgz#c7e785beb6bf0616ed4992785dc3658670425a39"
+ dependencies:
+ bitcore-lib "^0.15.0"
+ unorm "^1.3.3"
+
bl@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
@@ -1801,10 +1851,14 @@ bn.js@4.11.7:
version "4.11.7"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.7.tgz#ddb048e50d9482790094c13eb3fcfc833ce7ab46"
-bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.3, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^4.8.0:
+bn.js@=4.11.8, bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.3, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^4.8.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
+bn.js@^2.0.3:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-2.2.0.tgz#12162bc2ae71fc40a5626c33438f3a875cd37625"
+
body-parser@1.18.2, body-parser@^1.16.0, body-parser@^1.17.1:
version "1.18.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454"
@@ -1975,6 +2029,12 @@ browserslist@^2.1.2:
caniuse-lite "^1.0.30000792"
electron-to-chromium "^1.3.30"
+bs58@=4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
+ dependencies:
+ base-x "^3.0.2"
+
bs58@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d"
@@ -1996,6 +2056,10 @@ btoa@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.1.2.tgz#3e40b81663f81d2dd6596a4cb714a8dc16cfabe0"
+buffer-compare@=1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-compare/-/buffer-compare-1.1.1.tgz#5be7be853af89198d1f4ddc090d1d66a48aef596"
+
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
@@ -2032,7 +2096,7 @@ buffer@^3.0.1:
ieee754 "^1.1.4"
isarray "^1.0.0"
-buffer@^4.3.0:
+buffer@^4.3.0, buffer@^4.9.0:
version "4.9.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
dependencies:
@@ -2139,6 +2203,16 @@ call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
+caller-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
+ dependencies:
+ callsites "^0.2.0"
+
+callsites@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
+
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@@ -2332,6 +2406,10 @@ circular-json@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
+circular-json@^0.3.1:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
+
clap@^1.0.9:
version "1.2.3"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
@@ -2644,7 +2722,7 @@ concat-stream@^1.4.10, concat-stream@^1.5.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
-concat-stream@^1.5.1:
+concat-stream@^1.5.1, concat-stream@^1.6.0:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
dependencies:
@@ -2899,7 +2977,7 @@ copyfiles@^1.2.0:
copyfiles@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a"
+ resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a"
dependencies:
glob "^7.0.5"
minimatch "^3.0.3"
@@ -3054,7 +3132,7 @@ crypto-js@3.1.9-1, crypto-js@^3.1.9-1:
version "3.1.9-1"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8"
-crypto-js@^3.1.4:
+crypto-js@^3.1.4, crypto-js@^3.1.5:
version "3.1.8"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.8.tgz#715f070bf6014f2ae992a98b3929258b713f08d5"
@@ -3438,6 +3516,18 @@ defined@^1.0.0, defined@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+del@^2.0.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
+ dependencies:
+ globby "^5.0.0"
+ is-path-cwd "^1.0.0"
+ is-path-in-cwd "^1.0.0"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ rimraf "^2.2.8"
+
del@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
@@ -3581,6 +3671,12 @@ doctrine@^0.7.2:
esutils "^1.1.6"
isarray "0.0.1"
+doctrine@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ dependencies:
+ esutils "^2.0.2"
+
dom-helpers@^3.2.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
@@ -3716,7 +3812,7 @@ elliptic@6.3.3:
hash.js "^1.0.0"
inherits "^2.0.1"
-elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0:
+elliptic@=6.4.0, elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
dependencies:
@@ -3728,6 +3824,15 @@ elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
+elliptic@^3.1.0:
+ version "3.1.0"
+ resolved "http://registry.npmjs.org/elliptic/-/elliptic-3.1.0.tgz#c21682ef762769b56a74201609105da11d5f60cc"
+ dependencies:
+ bn.js "^2.0.3"
+ brorand "^1.0.1"
+ hash.js "^1.0.0"
+ inherits "^2.0.1"
+
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@@ -3920,6 +4025,67 @@ escope@^3.6.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
+eslint-scope@^3.7.1:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-visitor-keys@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
+
+eslint@^4.19.1:
+ version "4.19.1"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300"
+ dependencies:
+ ajv "^5.3.0"
+ babel-code-frame "^6.22.0"
+ chalk "^2.1.0"
+ concat-stream "^1.6.0"
+ cross-spawn "^5.1.0"
+ debug "^3.1.0"
+ doctrine "^2.1.0"
+ eslint-scope "^3.7.1"
+ eslint-visitor-keys "^1.0.0"
+ espree "^3.5.4"
+ esquery "^1.0.0"
+ esutils "^2.0.2"
+ file-entry-cache "^2.0.0"
+ functional-red-black-tree "^1.0.1"
+ glob "^7.1.2"
+ globals "^11.0.1"
+ ignore "^3.3.3"
+ imurmurhash "^0.1.4"
+ inquirer "^3.0.6"
+ is-resolvable "^1.0.0"
+ js-yaml "^3.9.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.3.0"
+ lodash "^4.17.4"
+ minimatch "^3.0.2"
+ mkdirp "^0.5.1"
+ natural-compare "^1.4.0"
+ optionator "^0.8.2"
+ path-is-inside "^1.0.2"
+ pluralize "^7.0.0"
+ progress "^2.0.0"
+ regexpp "^1.0.1"
+ require-uncached "^1.0.3"
+ semver "^5.3.0"
+ strip-ansi "^4.0.0"
+ strip-json-comments "~2.0.1"
+ table "4.0.2"
+ text-table "~0.2.0"
+
+espree@^3.5.4:
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+ dependencies:
+ acorn "^5.5.0"
+ acorn-jsx "^3.0.0"
+
esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
@@ -3928,6 +4094,12 @@ esprima@^4.0.0, esprima@~4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
+esquery@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+ dependencies:
+ estraverse "^4.0.0"
+
esrecurse@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
@@ -3938,7 +4110,7 @@ estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
-estraverse@^4.1.0, estraverse@^4.1.1:
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
@@ -3954,7 +4126,7 @@ etag@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
-eth-block-tracker@^2.2.2, eth-block-tracker@^2.3.0:
+eth-block-tracker@^2.2.2:
version "2.3.0"
resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-2.3.0.tgz#4cb782c8ef8fde2f5dc894921ae1f5c1077c35a4"
dependencies:
@@ -4027,6 +4199,22 @@ eth-lib@0.2.7:
elliptic "^6.4.0"
xhr-request-promise "^0.1.2"
+eth-lightwallet@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/eth-lightwallet/-/eth-lightwallet-3.0.1.tgz#297022932aa568f4e4eb0873bff257f5e5b78709"
+ dependencies:
+ bitcore-lib "^0.15.0"
+ bitcore-mnemonic "^1.5.0"
+ buffer "^4.9.0"
+ crypto-js "^3.1.5"
+ elliptic "^3.1.0"
+ ethereumjs-tx "^1.3.3"
+ ethereumjs-util "^5.1.1"
+ rlp "^2.0.0"
+ scrypt-async "^1.2.0"
+ tweetnacl "0.13.2"
+ web3 "0.20.2"
+
eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e"
@@ -4071,13 +4259,6 @@ ethereum-common@^0.0.18:
version "0.0.18"
resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f"
-ethereum-types@^0.0.2:
- version "0.0.2"
- resolved "https://registry.npmjs.org/ethereum-types/-/ethereum-types-0.0.2.tgz#6ef6faf46a24697cbf66b6c8a0ecf2095ce58c38"
- dependencies:
- "@types/node" "^8.0.53"
- bignumber.js "~4.1.0"
-
ethereumjs-abi@0.6.5, ethereumjs-abi@^0.6.4, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
version "0.6.5"
resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf"
@@ -4112,13 +4293,13 @@ ethereumjs-block@~1.2.2:
ethereumjs-util "^4.0.1"
merkle-patricia-tree "^2.1.2"
-ethereumjs-blockstream@^2.0.6:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/ethereumjs-blockstream/-/ethereumjs-blockstream-2.0.7.tgz#8e791d18d517f13e0ba928892dda545dc930936b"
+ethereumjs-blockstream@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/ethereumjs-blockstream/-/ethereumjs-blockstream-5.0.0.tgz#63bfe9185757329a32822d5815562eb1dcd75d71"
dependencies:
- immutable "3.8.1"
- source-map-support "0.4.14"
- uuid "3.0.1"
+ immutable "3.8.2"
+ source-map-support "0.5.6"
+ uuid "3.2.1"
ethereumjs-tx@0xProject/ethereumjs-tx#fake-tx-include-signature-by-default:
version "1.3.4"
@@ -4570,6 +4751,13 @@ figures@^2.0.0:
dependencies:
escape-string-regexp "^1.0.5"
+file-entry-cache@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
+ dependencies:
+ flat-cache "^1.2.1"
+ object-assign "^4.0.1"
+
file-type@3.9.0, file-type@^3.6.0, file-type@^3.8.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
@@ -4700,6 +4888,15 @@ flagged-respawn@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.0.tgz#4e79ae9b2eb38bf86b3bb56bf3e0a56aa5fcabd7"
+flat-cache@^1.2.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481"
+ dependencies:
+ circular-json "^0.3.1"
+ del "^2.0.2"
+ graceful-fs "^4.1.2"
+ write "^0.2.1"
+
flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
@@ -5206,10 +5403,25 @@ global@~4.3.0:
min-document "^2.19.0"
process "~0.5.1"
+globals@^11.0.1:
+ version "11.7.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
+
globals@^9.18.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+globby@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
+ dependencies:
+ array-union "^1.0.1"
+ arrify "^1.0.0"
+ glob "^7.0.3"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
globby@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
@@ -5791,6 +6003,10 @@ ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
+ignore@^3.3.3, ignore@^3.3.7:
+ version "3.3.10"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
+
ignore@^3.3.5:
version "3.3.7"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021"
@@ -5803,9 +6019,9 @@ immediate@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c"
-immutable@3.8.1:
- version "3.8.1"
- resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2"
+immutable@3.8.2:
+ version "3.8.2"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
import-lazy@^2.1.0:
version "2.1.0"
@@ -5862,7 +6078,7 @@ inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, i
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-inherits@2.0.1:
+inherits@2.0.1, inherits@=2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
@@ -5890,7 +6106,7 @@ inquirer@^0.8.2:
rx "^2.4.3"
through "^2.3.6"
-inquirer@^3.2.2:
+inquirer@^3.0.6, inquirer@^3.2.2:
version "3.3.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
dependencies:
@@ -6268,6 +6484,10 @@ is-relative@^1.0.0:
dependencies:
is-unc-path "^1.0.0"
+is-resolvable@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
+
is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
@@ -6495,6 +6715,13 @@ js-yaml@3.x, js-yaml@^3.4.2, js-yaml@^3.6.1, js-yaml@^3.7.0:
argparse "^1.0.7"
esprima "^4.0.0"
+js-yaml@^3.9.1:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
js-yaml@~3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
@@ -6594,6 +6821,10 @@ json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+
json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
@@ -6890,7 +7121,7 @@ levelup@~0.19.0:
semver "~5.1.0"
xtend "~3.0.0"
-levn@~0.3.0:
+levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
dependencies:
@@ -7207,7 +7438,7 @@ lodash@4.17.2:
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
-lodash@4.17.4:
+lodash@4.17.4, lodash@=4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -7830,6 +8061,10 @@ natives@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.3.tgz#44a579be64507ea2d6ed1ca04a9415915cf75558"
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
ncp@1.0.x:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246"
@@ -8126,6 +8361,10 @@ number-to-bn@1.7.0:
bn.js "4.11.6"
strip-hex-prefix "1.0.0"
+numeral@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506"
+
nyc@^11.0.1:
version "11.7.1"
resolved "https://registry.yarnpkg.com/nyc/-/nyc-11.7.1.tgz#7cb0a422e501b88ff2c1634341dec2560299d67b"
@@ -8310,7 +8549,7 @@ optimist@^0.6.1:
minimist "~0.0.1"
wordwrap "~0.0.2"
-optionator@^0.8.1:
+optionator@^0.8.1, optionator@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
dependencies:
@@ -8576,7 +8815,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
-path-is-inside@^1.0.1:
+path-is-inside@^1.0.1, path-is-inside@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
@@ -8704,6 +8943,10 @@ plur@^2.1.2:
dependencies:
irregular-plurals "^1.0.0"
+pluralize@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
+
polished@^1.9.2:
version "1.9.2"
resolved "https://registry.npmjs.org/polished/-/polished-1.9.2.tgz#d705cac66f3a3ed1bd38aad863e2c1e269baf6b6"
@@ -9890,6 +10133,10 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
+regexpp@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab"
+
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
@@ -10068,6 +10315,13 @@ require-package-name@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
+require-uncached@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
+ dependencies:
+ caller-path "^0.1.0"
+ resolve-from "^1.0.0"
+
requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
@@ -10089,6 +10343,10 @@ resolve-from@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+resolve-from@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
+
resolve-from@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
@@ -10215,7 +10473,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
run-s@^0.0.0:
version "0.0.0"
- resolved "https://registry.npmjs.org/run-s/-/run-s-0.0.0.tgz#599912be20c00ba7698655c9936d075d31b71754"
+ resolved "https://registry.yarnpkg.com/run-s/-/run-s-0.0.0.tgz#599912be20c00ba7698655c9936d075d31b71754"
rustbn.js@~0.1.1:
version "0.1.2"
@@ -10283,6 +10541,10 @@ scoped-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
+scrypt-async@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/scrypt-async/-/scrypt-async-1.3.1.tgz#a11fd6fac981b4b823ee01dee0221169500ddae9"
+
scrypt-js@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4"
@@ -10615,6 +10877,12 @@ slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+slice-ansi@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d"
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+
slide@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
@@ -10706,6 +10974,17 @@ solc@^0.4.23:
semver "^5.3.0"
yargs "^4.7.1"
+solhint@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/solhint/-/solhint-1.2.1.tgz#59a1416cef94da38d587f768a73536d6e3403dd3"
+ dependencies:
+ antlr4 "4.7.0"
+ commander "2.11.0"
+ eslint "^4.19.1"
+ glob "7.1.2"
+ ignore "^3.3.7"
+ lodash "^4.17.10"
+
solidity-parser-antlr@^0.2.12:
version "0.2.12"
resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.2.12.tgz#1154f183d5cdda2c7677549ee584dbdb7fb2269c"
@@ -10756,11 +11035,12 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
-source-map-support@0.4.14:
- version "0.4.14"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+source-map-support@0.5.6, source-map-support@^0.5.6:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13"
dependencies:
- source-map "^0.5.6"
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
source-map-support@^0.4.15:
version "0.4.18"
@@ -10774,13 +11054,6 @@ source-map-support@^0.5.0, source-map-support@^0.5.3:
dependencies:
source-map "^0.6.0"
-source-map-support@^0.5.6:
- version "0.5.6"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13"
- dependencies:
- buffer-from "^1.0.0"
- source-map "^0.6.0"
-
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@@ -11277,6 +11550,17 @@ symbol@~0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/symbol/-/symbol-0.3.1.tgz#b6f9a900d496a57f02408f22198c109dda063041"
+table@4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36"
+ dependencies:
+ ajv "^5.2.3"
+ ajv-keywords "^2.1.0"
+ chalk "^2.1.0"
+ lodash "^4.17.4"
+ slice-ansi "1.0.0"
+ string-width "^2.1.1"
+
tapable@^0.2.5, tapable@^0.2.7:
version "0.2.8"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
@@ -11416,7 +11700,7 @@ text-extensions@^1.0.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.7.0.tgz#faaaba2625ed746d568a23e4d0aacd9bf08a8b39"
-text-table@^0.2.0:
+text-table@^0.2.0, text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -11735,6 +12019,10 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
+tweetnacl@0.13.2:
+ version "0.13.2"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.13.2.tgz#453161770469d45cd266c36404e2bc99a8fa9944"
+
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
@@ -12187,14 +12475,14 @@ uuid@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
+uuid@3.2.1, uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
+
uuid@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
-uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
-
uvm@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/uvm/-/uvm-1.7.0.tgz#685d3a149ec7118fb73a73dfdc158ab46b0f0634"
@@ -12535,39 +12823,15 @@ web3-net@1.0.0-beta.34:
web3-core-method "1.0.0-beta.34"
web3-utils "1.0.0-beta.34"
-web3-provider-engine@^13.3.2:
- version "13.8.0"
- resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df"
- dependencies:
- async "^2.5.0"
- clone "^2.0.0"
- eth-block-tracker "^2.2.2"
- eth-sig-util "^1.4.2"
- ethereumjs-block "^1.2.2"
- ethereumjs-tx "^1.2.0"
- ethereumjs-util "^5.1.1"
- ethereumjs-vm "^2.0.2"
- fetch-ponyfill "^4.0.0"
- json-rpc-error "^2.0.0"
- json-stable-stringify "^1.0.1"
- promise-to-callback "^1.0.0"
- readable-stream "^2.2.9"
- request "^2.67.0"
- semaphore "^1.0.3"
- solc "^0.4.2"
- tape "^4.4.0"
- xhr "^2.2.0"
- xtend "^4.0.1"
-
-web3-provider-engine@^14.0.4:
- version "14.0.4"
- resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.0.4.tgz#6f96b71ea1b3a76cc67cd52007116c8d4b64465b"
+web3-provider-engine@14.0.6, web3-provider-engine@^14.0.6:
+ version "14.0.6"
+ resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.0.6.tgz#cbdd66fe20c0136a3a495cbe40d18b6c4160d5f0"
dependencies:
async "^2.5.0"
backoff "^2.5.0"
clone "^2.0.0"
cross-fetch "^2.1.0"
- eth-block-tracker "^2.3.0"
+ eth-block-tracker "^3.0.0"
eth-json-rpc-infura "^3.1.0"
eth-sig-util "^1.4.2"
ethereumjs-block "^1.2.2"
@@ -12585,29 +12849,27 @@ web3-provider-engine@^14.0.4:
xhr "^2.2.0"
xtend "^4.0.1"
-web3-provider-engine@^14.0.6:
- version "14.0.6"
- resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.0.6.tgz#cbdd66fe20c0136a3a495cbe40d18b6c4160d5f0"
+web3-provider-engine@^13.3.2:
+ version "13.8.0"
+ resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df"
dependencies:
async "^2.5.0"
- backoff "^2.5.0"
clone "^2.0.0"
- cross-fetch "^2.1.0"
- eth-block-tracker "^3.0.0"
- eth-json-rpc-infura "^3.1.0"
+ eth-block-tracker "^2.2.2"
eth-sig-util "^1.4.2"
ethereumjs-block "^1.2.2"
ethereumjs-tx "^1.2.0"
- ethereumjs-util "^5.1.5"
- ethereumjs-vm "^2.3.4"
+ ethereumjs-util "^5.1.1"
+ ethereumjs-vm "^2.0.2"
+ fetch-ponyfill "^4.0.0"
json-rpc-error "^2.0.0"
json-stable-stringify "^1.0.1"
promise-to-callback "^1.0.0"
readable-stream "^2.2.9"
request "^2.67.0"
semaphore "^1.0.3"
+ solc "^0.4.2"
tape "^4.4.0"
- ws "^5.1.1"
xhr "^2.2.0"
xtend "^4.0.1"
@@ -12661,21 +12923,21 @@ web3-utils@1.0.0-beta.34:
underscore "1.8.3"
utf8 "2.1.1"
-web3@^0.18.0:
- version "0.18.4"
- resolved "https://registry.yarnpkg.com/web3/-/web3-0.18.4.tgz#81ec1784145491f2eaa8955b31c06049e07c5e7d"
+web3@0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.2.tgz#c54dac5fc0e377399c04c1a6ecbb12e4513278d6"
dependencies:
- bignumber.js "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2"
+ bignumber.js "git+https://github.com/frozeman/bignumber.js-nolookahead.git"
crypto-js "^3.1.4"
utf8 "^2.1.1"
xhr2 "*"
xmlhttprequest "*"
-web3@^0.20.0:
- version "0.20.6"
- resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.6.tgz#3e97306ae024fb24e10a3d75c884302562215120"
+web3@^0.18.0:
+ version "0.18.4"
+ resolved "https://registry.yarnpkg.com/web3/-/web3-0.18.4.tgz#81ec1784145491f2eaa8955b31c06049e07c5e7d"
dependencies:
- bignumber.js "git+https://github.com/frozeman/bignumber.js-nolookahead.git"
+ bignumber.js "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2"
crypto-js "^3.1.4"
utf8 "^2.1.1"
xhr2 "*"
@@ -12964,6 +13226,12 @@ write-pkg@^3.1.0:
sort-keys "^2.0.0"
write-json-file "^2.2.0"
+write@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
+ dependencies:
+ mkdirp "^0.5.1"
+
ws@^3.0.0:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
@@ -13168,7 +13436,7 @@ yargs@^10.0.3:
yargs@^11.0.0:
version "11.0.0"
- resolved "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b"
dependencies:
cliui "^4.0.0"
decamelize "^1.1.1"