aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contract-wrappers
diff options
context:
space:
mode:
authorRemco Bloemen <remco@wicked.ventures>2018-11-09 01:32:40 +0800
committerRemco Bloemen <remco@wicked.ventures>2018-11-09 01:32:40 +0800
commitd71362af993d3797dbdbfcac245ad57f0086bce3 (patch)
tree888826fe23c2d06d6c9191fb3a238e14f9fe4aac /packages/contract-wrappers
parenta5665a68756c905637c551fc48c9b7011a55c237 (diff)
parentf6abc007ffb249e4bbf85b8a7a77309d43e0a147 (diff)
downloaddexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.gz
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.bz2
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.lz
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.xz
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.zst
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.zip
Merge remote-tracking branch 'origin/development' into feature/utils/prettybignum
Diffstat (limited to 'packages/contract-wrappers')
-rw-r--r--packages/contract-wrappers/CHANGELOG.json179
-rw-r--r--packages/contract-wrappers/CHANGELOG.md59
-rw-r--r--packages/contract-wrappers/README.md12
-rw-r--r--packages/contract-wrappers/package.json67
-rw-r--r--packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts2
-rw-r--r--packages/contract-wrappers/src/artifacts.ts25
-rw-r--r--packages/contract-wrappers/src/contract_wrappers.ts99
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts112
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts58
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts55
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts58
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts59
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts60
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts155
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts242
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts185
-rw-r--r--packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts77
-rw-r--r--packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts29
-rw-r--r--packages/contract-wrappers/src/globals.d.ts6
-rw-r--r--packages/contract-wrappers/src/index.ts110
-rw-r--r--packages/contract-wrappers/src/monorepo_scripts/postpublish.ts8
-rw-r--r--packages/contract-wrappers/src/schemas/contract_wrappers_config_schema.ts22
-rw-r--r--packages/contract-wrappers/src/schemas/contract_wrappers_private_network_config_schema.ts36
-rw-r--r--packages/contract-wrappers/src/schemas/contract_wrappers_public_network_config_schema.ts44
-rw-r--r--packages/contract-wrappers/src/types.ts66
-rw-r--r--packages/contract-wrappers/src/utils/assert.ts14
-rw-r--r--packages/contract-wrappers/src/utils/calldata_optimization_utils.ts2
-rw-r--r--packages/contract-wrappers/src/utils/constants.ts5
-rw-r--r--packages/contract-wrappers/src/utils/contract_addresses.ts15
-rw-r--r--packages/contract-wrappers/src/utils/decorators.ts21
-rw-r--r--packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts6
-rw-r--r--packages/contract-wrappers/src/utils/filter_utils.ts2
-rw-r--r--packages/contract-wrappers/src/utils/transaction_encoder.ts32
-rw-r--r--packages/contract-wrappers/src/utils/utils.ts12
-rw-r--r--packages/contract-wrappers/test/artifacts_test.ts43
-rw-r--r--packages/contract-wrappers/test/calldata_optimization_utils_test.ts3
-rw-r--r--packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts10
-rw-r--r--packages/contract-wrappers/test/erc20_wrapper_test.ts64
-rw-r--r--packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts10
-rw-r--r--packages/contract-wrappers/test/erc721_wrapper_test.ts57
-rw-r--r--packages/contract-wrappers/test/ether_token_wrapper_test.ts43
-rw-r--r--packages/contract-wrappers/test/exchange_wrapper_test.ts61
-rw-r--r--packages/contract-wrappers/test/forwarder_wrapper_test.ts99
-rw-r--r--packages/contract-wrappers/test/global_hooks.ts13
-rw-r--r--packages/contract-wrappers/test/order_validator_wrapper_test.ts146
-rw-r--r--packages/contract-wrappers/test/revert_validation_test.ts115
-rw-r--r--packages/contract-wrappers/test/subscription_test.ts35
-rw-r--r--packages/contract-wrappers/test/transaction_encoder_test.ts37
-rw-r--r--packages/contract-wrappers/test/utils/constants.ts3
-rw-r--r--packages/contract-wrappers/test/utils/migrate.ts18
-rw-r--r--packages/contract-wrappers/test/utils/token_utils.ts24
-rw-r--r--packages/contract-wrappers/test/utils/web3_wrapper.ts4
-rw-r--r--packages/contract-wrappers/tsconfig.json3
-rw-r--r--packages/contract-wrappers/tslint.json2
-rw-r--r--packages/contract-wrappers/typedoc-tsconfig.json7
55 files changed, 1742 insertions, 989 deletions
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index d50043b0d..9ff372e33 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,14 +1,187 @@
[
{
- "version": "1.0.1-rc.4",
+ "version": "3.0.1",
"changes": [
{
- "pr": 975,
- "note": "Added Transaction Encoder for use with 0x Exchange executeTransaction"
+ "note": "Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized.",
+ "pr": 1178
}
]
},
{
+ "version": "3.0.0",
+ "changes": [
+ {
+ "note": "Add optional validation to the forwarder wrapper methods"
+ },
+ {
+ "note": "Updated to use new modularized artifacts.",
+ "pr": 1105
+ },
+ {
+ "note": "Top-level `ContractWrappers` class has a new optional `contractAddresses` parameter.",
+ "pr": 1105
+ },
+ {
+ "note":
+ "Default contract addresses are no longer stored in artifacts and are instead loaded from the `@0xproject/contract-addresses` package.",
+ "pr": 1105
+ },
+ {
+ "note":
+ "Most contract addresses are now defined at instantiation time and are available as properties (e.g., `exchangeWrapper.address`) instead of methods (e.g., `exchangeWrapper.getContractAddress()`).",
+ "pr": 1105
+ },
+ {
+ "note":
+ "Removed `setProvider` method in top-level `ContractWrapper` class and added new `unsubscribeAll` method.",
+ "pr": 1105
+ },
+ {
+ "note":
+ "Some properties and methods have been renamed. For example, some methods that previously could throw no longer can, and so their names have been updated accordingly.",
+ "pr": 1105
+ },
+ {
+ "note":
+ "Removed ContractNotFound errors. Checking for this error was somewhat ineffecient. Relevant methods/functions now return the default error from web3-wrapper, which we feel provides enough information.",
+ "pr": 1105
+ },
+ {
+ "note": "Add `ForwarderWrapperError` to public interface",
+ "pr": 1147
+ },
+ {
+ "note": "Add `ContractWrapperError.SignatureRequestDenied` to public interface",
+ "pr": 1147
+ }
+ ],
+ "timestamp": 1539871071
+ },
+ {
+ "version": "2.0.2",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1538693146
+ },
+ {
+ "timestamp": 1538157789,
+ "version": "2.0.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
+ "version": "2.0.0",
+ "changes": [
+ {
+ "note":
+ "Fixes dropped events in subscriptions by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too.",
+ "pr": 1080
+ },
+ {
+ "note":
+ "Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it",
+ "pr": 1080
+ }
+ ],
+ "timestamp": 1537907159
+ },
+ {
+ "version": "1.0.5",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1537875740
+ },
+ {
+ "version": "1.0.4",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ],
+ "timestamp": 1537541580
+ },
+ {
+ "version": "1.0.3",
+ "changes": [
+ {
+ "note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts."
+ }
+ ],
+ "timestamp": 1537369748
+ },
+ {
+ "version": "1.0.2",
+ "changes": [
+ {
+ "note": "Add ZRX & WETH mainnet contract addresses into the included artifacts"
+ }
+ ],
+ "timestamp": 1537265493
+ },
+ {
+ "version": "1.0.1",
+ "changes": [
+ {
+ "note": "Add `OrderValidatorWrapper`"
+ },
+ {
+ "note":
+ "Fix bug where contracts not deployed on a network showed an `EXCHANGE_CONTRACT_DOES_NOT_EXIST` error instead of `CONTRACT_NOT_DEPLOYED_ON_NETWORK`",
+ "pr": 1044
+ },
+ {
+ "note":
+ "Export `AssetBalanceAndProxyAllowanceFetcher` and `OrderFilledCancelledFetcher` implementations",
+ "pr": 1054
+ },
+ {
+ "note":
+ "Add `validateOrderFillableOrThrowAsync` and `validateFillOrderThrowIfInvalidAsync` to ExchangeWrapper",
+ "pr": 1054
+ }
+ ],
+ "timestamp": 1536142250
+ },
+ {
+ "version": "1.0.1-rc.5",
+ "changes": [
+ {
+ "note": "Fix missing `BlockParamLiteral` type import issue"
+ }
+ ],
+ "timestamp": 1535377027
+ },
+ {
+ "version": "1.0.1-rc.4",
+ "changes": [
+ {
+ "note":
+ "Export missing types: `TransactionEncoder`, `ContractAbi`, `JSONRPCRequestPayload`, `JSONRPCResponsePayload`, `JSONRPCErrorCallback`, `AbiDefinition`, `FunctionAbi`, `EventAbi`, `EventParameter`, `DecodedLogArgs`, `MethodAbi`, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability`, `StateMutability` & `ExchangeSignatureValidatorApprovalEventArgs`",
+ "pr": 924
+ },
+ {
+ "note":
+ "Remove superfluous exported types: `ContractEvent`, `Token`, `OrderFillRequest`, `ContractEventArgs`, `LogEvent`, `OnOrderStateChangeCallback`, `ECSignature`, `OrderStateValid`, `OrderStateInvalid`, `OrderState`, `FilterObject`, `TransactionReceipt` & `TransactionReceiptWithDecodedLogs`",
+ "pr": 924
+ },
+ {
+ "note": "Added Transaction Encoder for use with 0x Exchange executeTransaction",
+ "pr": 975
+ }
+ ],
+ "timestamp": 1535133899
+ },
+ {
"version": "1.0.1-rc.3",
"changes": [
{
diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md
index c2ad7218e..6f3005831 100644
--- a/packages/contract-wrappers/CHANGELOG.md
+++ b/packages/contract-wrappers/CHANGELOG.md
@@ -5,7 +5,64 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
-## v1.0.1-rc.3 - _August 13, 2018_
+## v3.0.0 - _October 18, 2018_
+
+ * Add optional validation to the forwarder wrapper methods
+ * Updated to use new modularized artifacts. (#1105)
+ * Top-level `ContractWrappers` class has a new optional `contractAddresses` parameter. (#1105)
+ * Default contract addresses are no longer stored in artifacts and are instead loaded from the `@0xproject/contract-addresses` package. (#1105)
+ * Most contract addresses are now defined at instantiation time and are available as properties (e.g., `exchangeWrapper.address`) instead of methods (e.g., `exchangeWrapper.getContractAddress()`). (#1105)
+ * Removed `setProvider` method in top-level `ContractWrapper` class and added new `unsubscribeAll` method. (#1105)
+ * Some properties and methods have been renamed. For example, some methods that previously could throw no longer can, and so their names have been updated accordingly. (#1105)
+ * Removed ContractNotFound errors. Checking for this error was somewhat ineffecient. Relevant methods/functions now return the default error from web3-wrapper, which we feel provides enough information. (#1105)
+
+## v2.0.2 - _October 4, 2018_
+
+ * Dependencies updated
+
+## v2.0.1 - _September 28, 2018_
+
+ * Dependencies updated
+
+## v2.0.0 - _September 25, 2018_
+
+ * Fixes dropped events in subscriptions by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too. (#1080)
+ * Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it (#1080)
+
+## v1.0.5 - _September 25, 2018_
+
+ * Dependencies updated
+
+## v1.0.4 - _September 21, 2018_
+
+ * Dependencies updated
+
+## v1.0.3 - _September 19, 2018_
+
+ * Drastically reduce the bundle size by removing unused parts of included contract artifacts.
+
+## v1.0.2 - _September 18, 2018_
+
+ * Add ZRX & WETH mainnet contract addresses into the included artifacts
+
+## v1.0.1 - _September 5, 2018_
+
+ * Add `OrderValidatorWrapper`
+ * Fix bug where contracts not deployed on a network showed an `EXCHANGE_CONTRACT_DOES_NOT_EXIST` error instead of `CONTRACT_NOT_DEPLOYED_ON_NETWORK` (#1044)
+ * Export `AssetBalanceAndProxyAllowanceFetcher` and `OrderFilledCancelledFetcher` implementations (#1054)
+ * Add `validateOrderFillableOrThrowAsync` and `validateFillOrderThrowIfInvalidAsync` to ExchangeWrapper (#1054)
+
+## v1.0.1-rc.5 - _August 27, 2018_
+
+ * Fix missing `BlockParamLiteral` type import issue
+
+## v1.0.1-rc.4 - _August 24, 2018_
+
+ * Export missing types: `TransactionEncoder`, `ContractAbi`, `JSONRPCRequestPayload`, `JSONRPCResponsePayload`, `JSONRPCErrorCallback`, `AbiDefinition`, `FunctionAbi`, `EventAbi`, `EventParameter`, `DecodedLogArgs`, `MethodAbi`, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability`, `StateMutability` & `ExchangeSignatureValidatorApprovalEventArgs` (#924)
+ * Remove superfluous exported types: `ContractEvent`, `Token`, `OrderFillRequest`, `ContractEventArgs`, `LogEvent`, `OnOrderStateChangeCallback`, `ECSignature`, `OrderStateValid`, `OrderStateInvalid`, `OrderState`, `FilterObject`, `TransactionReceipt` & `TransactionReceiptWithDecodedLogs` (#924)
+ * Added Transaction Encoder for use with 0x Exchange executeTransaction (#975)
+
+## v1.0.1-rc.3 - _August 14, 2018_
* Added strict encoding/decoding checks for sendTransaction and call (#915)
* Add ForwarderWrapper (#934)
diff --git a/packages/contract-wrappers/README.md b/packages/contract-wrappers/README.md
index 6153f798e..36f2f48fb 100644
--- a/packages/contract-wrappers/README.md
+++ b/packages/contract-wrappers/README.md
@@ -1,4 +1,4 @@
-## @0xproject/contract-wrappers
+## @0x/contract-wrappers
Smart TS wrappers for 0x smart contracts. The wrappers have simplified interfaces, perform client-side validation on transactions and throw helpful error messages.
@@ -9,20 +9,20 @@ Smart TS wrappers for 0x smart contracts. The wrappers have simplified interface
**Install**
```bash
-npm install @0xproject/contract-wrappers --save
+npm install @0x/contract-wrappers --save
```
**Import**
```javascript
-import { ContractWrappers } from '@0xproject/contract-wrappers';
+import { ContractWrappers } from '@0x/contract-wrappers';
```
If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
```json
"compilerOptions": {
- "typeRoots": ["node_modules/@0xproject/typescript-typings/types", "node_modules/@types"],
+ "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"],
}
```
@@ -51,13 +51,13 @@ yarn install
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
-PKG=@0xproject/contract-wrappers yarn build
+PKG=@0x/contract-wrappers yarn build
```
Or continuously rebuild on change:
```bash
-PKG=@0xproject/contract-wrappers yarn watch
+PKG=@0x/contract-wrappers yarn watch
```
```bash
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index 3399c7a9f..178675763 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -1,6 +1,6 @@
{
- "name": "@0xproject/contract-wrappers",
- "version": "1.0.1-rc.3",
+ "name": "@0x/contract-wrappers",
+ "version": "3.0.0",
"description": "Smart TS wrappers for 0x smart contracts",
"keywords": [
"0xproject",
@@ -11,26 +11,22 @@
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
- "watch_without_deps": "yarn pre_build && tsc -w",
- "build": "yarn pre_build && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
- "pre_build": "run-s update_artifacts_v2_beta update_artifacts_v2 generate_contract_wrappers copy_artifacts",
- "generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy|Forwarder).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
- "lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
+ "build": "tsc -b",
+ "build:ci": "yarn build",
+ "lint": "tslint --format stylish --project . --exclude **/lib/**/*",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "update_artifacts_v2_beta": "for i in ${npm_package_config_contracts_v2_beta}; do copyfiles -u 4 ../migrations/artifacts/2.0.0-beta-testnet/$i.json src/artifacts; done;",
- "update_artifacts_v2": "for i in ${npm_package_config_contracts_v2}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json src/artifacts; done;",
- "copy_artifacts": "copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts",
- "clean": "shx rm -rf _bundles lib test_temp scripts test/artifacts src/contract_wrappers/generated src/artifacts",
+ "clean": "shx rm -rf _bundles lib test_temp generated_docs",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
- "manual:postpublish": "yarn build; node ./scripts/postpublish.js"
+ "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
- "contracts_v2_beta": "AssetProxyOwner Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken Forwarder",
- "contracts_v2": "DummyERC20Token DummyERC721Token"
+ "postpublish": {
+ "assets": []
+ }
},
"repository": {
"type": "git",
@@ -41,23 +37,19 @@
"node": ">=6.0.0"
},
"devDependencies": {
- "@0xproject/abi-gen": "^1.0.5",
- "@0xproject/dev-utils": "^1.0.4",
- "@0xproject/migrations": "^1.0.4",
- "@0xproject/monorepo-scripts": "^1.0.5",
- "@0xproject/sol-compiler": "^1.0.5",
- "@0xproject/subproviders": "^1.0.5",
- "@0xproject/tslint-config": "^1.0.5",
+ "@0x/dev-utils": "^1.0.13",
+ "@0x/migrations": "^2.0.0",
+ "@0x/subproviders": "^2.1.0",
+ "@0x/tslint-config": "^1.0.9",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
- "@types/node": "^8.0.53",
+ "@types/node": "*",
"@types/sinon": "^2.2.2",
"@types/uuid": "^3.4.2",
- "awesome-typescript-loader": "^3.1.3",
+ "@types/web3-provider-engine": "^14.0.0",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
- "copyfiles": "^2.0.0",
"dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.1.0",
@@ -68,23 +60,26 @@
"sinon": "^4.0.0",
"source-map-support": "^0.5.0",
"tslint": "5.11.0",
+ "typedoc": "0.13.0",
"typescript": "3.0.1",
"web3-provider-engine": "14.0.6"
},
"dependencies": {
- "@0xproject/assert": "^1.0.5",
- "@0xproject/base-contract": "^2.0.0-rc.1",
- "@0xproject/fill-scenarios": "^1.0.1-rc.3",
- "@0xproject/json-schemas": "^1.0.1-rc.4",
- "@0xproject/order-utils": "^1.0.1-rc.3",
- "@0xproject/types": "^1.0.1-rc.4",
- "@0xproject/typescript-typings": "^1.0.4",
- "@0xproject/utils": "^1.0.5",
- "@0xproject/web3-wrapper": "^1.2.0",
- "ethereum-types": "^1.0.4",
- "ethereumjs-blockstream": "5.0.0",
+ "@0x/abi-gen-wrappers": "^1.0.1",
+ "@0x/assert": "^1.0.14",
+ "@0x/contract-addresses": "^1.0.1",
+ "@0x/contract-artifacts": "^1.0.1",
+ "@0x/fill-scenarios": "^1.0.8",
+ "@0x/json-schemas": "^2.0.0",
+ "@0x/order-utils": "^2.0.0",
+ "@0x/types": "^1.2.0",
+ "@0x/typescript-typings": "^3.0.3",
+ "@0x/utils": "^2.0.3",
+ "@0x/web3-wrapper": "^3.1.0",
+ "ethereum-types": "^1.1.1",
+ "ethereumjs-blockstream": "6.0.0",
"ethereumjs-util": "^5.1.1",
- "ethers": "3.0.22",
+ "ethers": "~4.0.4",
"js-sha3": "^0.7.0",
"lodash": "^4.17.5",
"uuid": "^3.1.0"
diff --git a/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts b/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts
index 1f139f1ef..b095c8e79 100644
--- a/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts
+++ b/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts
@@ -1,4 +1,4 @@
-import { BigNumber } from '@0xproject/utils';
+import { BigNumber } from '@0x/utils';
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
diff --git a/packages/contract-wrappers/src/artifacts.ts b/packages/contract-wrappers/src/artifacts.ts
deleted file mode 100644
index 2481b311a..000000000
--- a/packages/contract-wrappers/src/artifacts.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ContractArtifact } from '@0xproject/sol-compiler';
-
-import * as DummyERC20Token from './artifacts/DummyERC20Token.json';
-import * as DummyERC721Token from './artifacts/DummyERC721Token.json';
-import * as ERC20Proxy from './artifacts/ERC20Proxy.json';
-import * as ERC20Token from './artifacts/ERC20Token.json';
-import * as ERC721Proxy from './artifacts/ERC721Proxy.json';
-import * as ERC721Token from './artifacts/ERC721Token.json';
-import * as Exchange from './artifacts/Exchange.json';
-import * as Forwarder from './artifacts/Forwarder.json';
-import * as EtherToken from './artifacts/WETH9.json';
-import * as ZRXToken from './artifacts/ZRXToken.json';
-
-export const artifacts = {
- ZRXToken: (ZRXToken as any) as ContractArtifact,
- DummyERC20Token: (DummyERC20Token as any) as ContractArtifact,
- DummyERC721Token: (DummyERC721Token as any) as ContractArtifact,
- ERC20Token: (ERC20Token as any) as ContractArtifact,
- ERC721Token: (ERC721Token as any) as ContractArtifact,
- Exchange: (Exchange as any) as ContractArtifact,
- EtherToken: (EtherToken as any) as ContractArtifact,
- ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
- ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
- Forwarder: (Forwarder as any) as ContractArtifact,
-};
diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts
index 4277a0746..0c535bd5c 100644
--- a/packages/contract-wrappers/src/contract_wrappers.ts
+++ b/packages/contract-wrappers/src/contract_wrappers.ts
@@ -1,10 +1,17 @@
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import {
+ ERC20Proxy,
+ ERC20Token,
+ ERC721Proxy,
+ ERC721Token,
+ Exchange,
+ Forwarder,
+ OrderValidator,
+ WETH9,
+} from '@0x/contract-artifacts';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
-import { constants } from './utils/constants';
-
-import { artifacts } from './artifacts';
import { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
import { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper';
import { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
@@ -12,11 +19,13 @@ import { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper';
import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
import { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
+import { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
import { ContractWrappersConfigSchema } from './schemas/contract_wrappers_config_schema';
-import { contractWrappersPrivateNetworkConfigSchema } from './schemas/contract_wrappers_private_network_config_schema';
-import { contractWrappersPublicNetworkConfigSchema } from './schemas/contract_wrappers_public_network_config_schema';
import { ContractWrappersConfig } from './types';
import { assert } from './utils/assert';
+import { constants } from './utils/constants';
+import { _getDefaultContractAddresses } from './utils/contract_addresses';
+
/**
* The ContractWrappers class contains smart contract wrappers helpful when building on 0x protocol.
*/
@@ -52,39 +61,47 @@ export class ContractWrappers {
* An instance of the ForwarderWrapper class containing methods for interacting with any Forwarder smart contract.
*/
public forwarder: ForwarderWrapper;
+ /**
+ * An instance of the OrderValidatorWrapper class containing methods for interacting with any OrderValidator smart contract.
+ */
+ public orderValidator: OrderValidatorWrapper;
- private _web3Wrapper: Web3Wrapper;
+ private readonly _web3Wrapper: Web3Wrapper;
/**
* Instantiates a new ContractWrappers instance.
- * @param provider The Provider instance you would like the 0x.js library to use for interacting with
+ * @param provider The Provider instance you would like the contract-wrappers library to use for interacting with
* the Ethereum network.
* @param config The configuration object. Look up the type for the description.
* @return An instance of the ContractWrappers class.
*/
constructor(provider: Provider, config: ContractWrappersConfig) {
assert.isWeb3Provider('provider', provider);
- assert.doesConformToSchema('config', config, ContractWrappersConfigSchema, [
- contractWrappersPrivateNetworkConfigSchema,
- contractWrappersPublicNetworkConfigSchema,
- ]);
- const artifactJSONs = _.values(artifacts);
- const abiArrays = _.map(artifactJSONs, artifact => artifact.compilerOutput.abi);
+ assert.doesConformToSchema('config', config, ContractWrappersConfigSchema);
const txDefaults = {
gasPrice: config.gasPrice,
};
this._web3Wrapper = new Web3Wrapper(provider, txDefaults);
- _.forEach(abiArrays, abi => {
- this._web3Wrapper.abiDecoder.addABI(abi);
+ const artifactsArray = [
+ ERC20Proxy,
+ ERC20Token,
+ ERC721Proxy,
+ ERC721Token,
+ Exchange,
+ Forwarder,
+ OrderValidator,
+ WETH9,
+ ];
+ _.forEach(artifactsArray, artifact => {
+ this._web3Wrapper.abiDecoder.addABI(artifact.compilerOutput.abi);
});
const blockPollingIntervalMs = _.isUndefined(config.blockPollingIntervalMs)
? constants.DEFAULT_BLOCK_POLLING_INTERVAL
: config.blockPollingIntervalMs;
- this.erc20Proxy = new ERC20ProxyWrapper(this._web3Wrapper, config.networkId, config.erc20ProxyContractAddress);
- this.erc721Proxy = new ERC721ProxyWrapper(
- this._web3Wrapper,
- config.networkId,
- config.erc721ProxyContractAddress,
- );
+ const contractAddresses = _.isUndefined(config.contractAddresses)
+ ? _getDefaultContractAddresses(config.networkId)
+ : config.contractAddresses;
+ this.erc20Proxy = new ERC20ProxyWrapper(this._web3Wrapper, config.networkId, contractAddresses.erc20Proxy);
+ this.erc721Proxy = new ERC721ProxyWrapper(this._web3Wrapper, config.networkId, contractAddresses.erc721Proxy);
this.erc20Token = new ERC20TokenWrapper(
this._web3Wrapper,
config.networkId,
@@ -106,36 +123,36 @@ export class ContractWrappers {
this.exchange = new ExchangeWrapper(
this._web3Wrapper,
config.networkId,
- config.exchangeContractAddress,
- config.zrxContractAddress,
+ this.erc20Token,
+ this.erc721Token,
+ contractAddresses.exchange,
+ contractAddresses.zrxToken,
blockPollingIntervalMs,
);
this.forwarder = new ForwarderWrapper(
this._web3Wrapper,
config.networkId,
- config.forwarderContractAddress,
- config.zrxContractAddress,
+ contractAddresses.forwarder,
+ contractAddresses.zrxToken,
+ contractAddresses.etherToken,
+ );
+ this.orderValidator = new OrderValidatorWrapper(
+ this._web3Wrapper,
+ config.networkId,
+ contractAddresses.orderValidator,
);
}
/**
- * Sets a new web3 provider for 0x.js. Updating the provider will stop all
- * subscriptions so you will need to re-subscribe to all events relevant to your app after this call.
- * @param provider The Web3Provider you would like the 0x.js library to use from now on.
- * @param networkId The id of the network your provider is connected to
+ * Unsubscribes from all subscriptions for all contracts.
*/
- public setProvider(provider: Provider, networkId: number): void {
- this._web3Wrapper.setProvider(provider);
- (this.exchange as any)._invalidateContractInstances();
- (this.exchange as any)._setNetworkId(networkId);
- (this.erc20Token as any)._invalidateContractInstances();
- (this.erc20Token as any)._setNetworkId(networkId);
- (this.erc20Proxy as any)._invalidateContractInstance();
- (this.erc20Proxy as any)._setNetworkId(networkId);
- (this.etherToken as any)._invalidateContractInstance();
- (this.etherToken as any)._setNetworkId(networkId);
+ public unsubscribeAll(): void {
+ this.exchange.unsubscribeAll();
+ this.erc20Token.unsubscribeAll();
+ this.erc721Token.unsubscribeAll();
+ this.etherToken.unsubscribeAll();
}
/**
- * Get the provider instance currently used by 0x.js
+ * Get the provider instance currently used by contract-wrappers
* @return Web3 provider instance
*/
public getProvider(): Provider {
diff --git a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
index daf70253a..749aaae10 100644
--- a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts
@@ -1,7 +1,14 @@
-import { ContractArtifact } from '@0xproject/sol-compiler';
-import { AbiDecoder, intervalUtils, logUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import { BlockParamLiteral, ContractAbi, FilterObject, LogEntry, LogWithDecodedArgs, RawLog } from 'ethereum-types';
+import { AbiDecoder, intervalUtils, logUtils } from '@0x/utils';
+import { marshaller, Web3Wrapper } from '@0x/web3-wrapper';
+import {
+ BlockParamLiteral,
+ ContractAbi,
+ FilterObject,
+ LogEntry,
+ LogWithDecodedArgs,
+ RawLog,
+ RawLogEntry,
+} from 'ethereum-types';
import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
import * as _ from 'lodash';
@@ -16,27 +23,15 @@ import {
import { constants } from '../utils/constants';
import { filterUtils } from '../utils/filter_utils';
-const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
- [contractName: string]: ContractWrappersError;
-} = {
- ZRX: ContractWrappersError.ZRXContractDoesNotExist,
- EtherToken: ContractWrappersError.EtherTokenContractDoesNotExist,
- ERC20Token: ContractWrappersError.ERC20TokenContractDoesNotExist,
- ERC20Proxy: ContractWrappersError.ERC20ProxyContractDoesNotExist,
- ERC721Token: ContractWrappersError.ERC721TokenContractDoesNotExist,
- ERC721Proxy: ContractWrappersError.ERC721ProxyContractDoesNotExist,
- Exchange: ContractWrappersError.ExchangeContractDoesNotExist,
-};
-
export abstract class ContractWrapper {
public abstract abi: ContractAbi;
- protected _web3Wrapper: Web3Wrapper;
protected _networkId: number;
+ protected _web3Wrapper: Web3Wrapper;
private _blockAndLogStreamerIfExists: BlockAndLogStreamer<Block, Log> | undefined;
- private _blockPollingIntervalMs: number;
+ private readonly _blockPollingIntervalMs: number;
private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
- private _filters: { [filterToken: string]: FilterObject };
- private _filterCallbacks: {
+ private readonly _filters: { [filterToken: string]: FilterObject };
+ private readonly _filterCallbacks: {
[filterToken: string]: EventCallback<ContractEventArgs>;
};
private _onLogAddedSubscriptionToken: string | undefined;
@@ -116,38 +111,8 @@ export abstract class ContractWrapper {
const logWithDecodedArgs = abiDecoder.tryToDecodeLogOrNoop(log);
return logWithDecodedArgs;
}
- protected async _getContractAbiAndAddressFromArtifactsAsync(
- artifact: ContractArtifact,
- addressIfExists?: string,
- ): Promise<[ContractAbi, string]> {
- let contractAddress: string;
- if (_.isUndefined(addressIfExists)) {
- if (_.isUndefined(artifact.networks[this._networkId])) {
- throw new Error(ContractWrappersError.ContractNotDeployedOnNetwork);
- }
- contractAddress = artifact.networks[this._networkId].address.toLowerCase();
- } else {
- contractAddress = addressIfExists;
- }
- const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(contractAddress);
- if (!doesContractExist) {
- throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contractName]);
- }
- const abiAndAddress: [ContractAbi, string] = [artifact.compilerOutput.abi, contractAddress];
- return abiAndAddress;
- }
- protected _getContractAddress(artifact: ContractArtifact, addressIfExists?: string): string {
- if (_.isUndefined(addressIfExists)) {
- const contractAddress = artifact.networks[this._networkId].address;
- if (_.isUndefined(contractAddress)) {
- throw new Error(ContractWrappersError.ExchangeContractDoesNotExist);
- }
- return contractAddress;
- } else {
- return addressIfExists;
- }
- }
- private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, log: LogEntry): void {
+ private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, rawLog: RawLogEntry): void {
+ const log: LogEntry = marshaller.unmarshalLog(rawLog);
_.forEach(this._filters, (filter: FilterObject, filterToken: string) => {
if (filterUtils.matchesFilter(log, filter)) {
const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
@@ -164,8 +129,8 @@ export abstract class ContractWrapper {
throw new Error(ContractWrappersError.SubscriptionAlreadyPresent);
}
this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
- this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
- this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
+ this._blockstreamGetBlockOrNullAsync.bind(this),
+ this._blockstreamGetLogsAsync.bind(this),
ContractWrapper._onBlockAndLogStreamerError.bind(this, isVerbose),
);
const catchAllLogFilter = {};
@@ -184,13 +149,31 @@ export abstract class ContractWrapper {
this._onLogStateChanged.bind(this, isRemoved),
);
}
- // HACK: This should be a package-scoped method (which doesn't exist in TS)
- // We don't want this method available in the public interface for all classes
- // who inherit from ContractWrapper, and it is only used by the internal implementation
- // of those higher classes.
- // tslint:disable-next-line:no-unused-variable
- private _setNetworkId(networkId: number): void {
- this._networkId = networkId;
+ // This method only exists in order to comply with the expected interface of Blockstream's constructor
+ private async _blockstreamGetBlockOrNullAsync(hash: string): Promise<Block | null> {
+ const shouldIncludeTransactionData = false;
+ const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync<Block | null>({
+ method: 'eth_getBlockByHash',
+ params: [hash, shouldIncludeTransactionData],
+ });
+ return blockOrNull;
+ }
+ // This method only exists in order to comply with the expected interface of Blockstream's constructor
+ private async _blockstreamGetLatestBlockOrNullAsync(): Promise<Block | null> {
+ const shouldIncludeTransactionData = false;
+ const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync<Block | null>({
+ method: 'eth_getBlockByNumber',
+ params: [BlockParamLiteral.Latest, shouldIncludeTransactionData],
+ });
+ return blockOrNull;
+ }
+ // This method only exists in order to comply with the expected interface of Blockstream's constructor
+ private async _blockstreamGetLogsAsync(filterOptions: FilterObject): Promise<RawLogEntry[]> {
+ const logs = await this._web3Wrapper.sendRawPayloadAsync<RawLogEntry[]>({
+ method: 'eth_getLogs',
+ params: [filterOptions],
+ });
+ return logs as RawLogEntry[];
}
private _stopBlockAndLogStream(): void {
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
@@ -202,11 +185,14 @@ export abstract class ContractWrapper {
delete this._blockAndLogStreamerIfExists;
}
private async _reconcileBlockAsync(): Promise<void> {
- const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
+ const latestBlockOrNull = await this._blockstreamGetLatestBlockOrNullAsync();
+ if (_.isNull(latestBlockOrNull)) {
+ return; // noop
+ }
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
- await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
+ await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlockOrNull);
}
}
}
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts
index 821d1a8a2..45460bd6d 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts
@@ -1,31 +1,42 @@
-import { AssetProxyId } from '@0xproject/types';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ERC20ProxyContract } from '@0x/abi-gen-wrappers';
+import { ERC20Proxy } from '@0x/contract-artifacts';
+import { AssetProxyId } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
import { assert } from '../utils/assert';
+import { _getDefaultContractAddresses } from '../utils/contract_addresses';
import { ContractWrapper } from './contract_wrapper';
-import { ERC20ProxyContract } from './generated/erc20_proxy';
/**
* This class includes the functionality related to interacting with the ERC20Proxy contract.
*/
export class ERC20ProxyWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.ERC20Proxy.compilerOutput.abi;
+ public abi: ContractAbi = ERC20Proxy.compilerOutput.abi;
+ public address: string;
private _erc20ProxyContractIfExists?: ERC20ProxyContract;
- private _contractAddressIfExists?: string;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
+ /**
+ * Instantiate ERC20ProxyWrapper
+ * @param web3Wrapper Web3Wrapper instance to use
+ * @param networkId Desired networkId
+ * @param address The address of the ERC20Proxy contract. If undefined, will
+ * default to the known address corresponding to the networkId.
+ */
+ constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) {
super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
+ this.address = _.isUndefined(address) ? _getDefaultContractAddresses(networkId).erc20Proxy : address;
}
/**
* Get the 4 bytes ID of this asset proxy
* @return Proxy id
*/
public async getProxyIdAsync(): Promise<AssetProxyId> {
- const ERC20ProxyContractInstance = await this._getERC20ProxyContractAsync();
+ const ERC20ProxyContractInstance = this._getERC20ProxyContract();
+ // Note(albrow): Below is a TSLint false positive. Code won't compile if
+ // you remove the type assertion.
+ /* tslint:disable-next-line:no-unnecessary-type-assertion */
const proxyId = (await ERC20ProxyContractInstance.getProxyId.callAsync()) as AssetProxyId;
return proxyId;
}
@@ -37,7 +48,7 @@ export class ERC20ProxyWrapper extends ContractWrapper {
public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress);
const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase();
- const ERC20ProxyContractInstance = await this._getERC20ProxyContractAsync();
+ const ERC20ProxyContractInstance = this._getERC20ProxyContract();
const isAuthorized = await ERC20ProxyContractInstance.authorized.callAsync(normalizedExchangeContractAddress);
return isAuthorized;
}
@@ -46,36 +57,17 @@ export class ERC20ProxyWrapper extends ContractWrapper {
* @return The list of authorized addresses.
*/
public async getAuthorizedAddressesAsync(): Promise<string[]> {
- const ERC20ProxyContractInstance = await this._getERC20ProxyContractAsync();
+ const ERC20ProxyContractInstance = this._getERC20ProxyContract();
const authorizedAddresses = await ERC20ProxyContractInstance.getAuthorizedAddresses.callAsync();
return authorizedAddresses;
}
- /**
- * Retrieves the Ethereum address of the ERC20Proxy contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the ERC20Proxy contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ERC20Proxy, this._contractAddressIfExists);
- return contractAddress;
- }
- // HACK: We don't want this method to be visible to the other units within that package but not to the end user.
- // TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
- // tslint:disable-next-line:no-unused-variable
- private _invalidateContractInstance(): void {
- delete this._erc20ProxyContractIfExists;
- }
- private async _getERC20ProxyContractAsync(): Promise<ERC20ProxyContract> {
+ private _getERC20ProxyContract(): ERC20ProxyContract {
if (!_.isUndefined(this._erc20ProxyContractIfExists)) {
return this._erc20ProxyContractIfExists;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.ERC20Proxy,
- this._contractAddressIfExists,
- );
const contractInstance = new ERC20ProxyContract(
- abi,
- address,
+ this.abi,
+ this.address,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts
index 17bda5085..5e0ec1951 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts
@@ -1,10 +1,11 @@
-import { schemas } from '@0xproject/json-schemas';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ERC20TokenContract, ERC20TokenEventArgs, ERC20TokenEvents } from '@0x/abi-gen-wrappers';
+import { ERC20Token } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
import { methodOptsSchema } from '../schemas/method_opts_schema';
import { txOptsSchema } from '../schemas/tx_opts_schema';
import {
@@ -17,12 +18,10 @@ import {
} from '../types';
import { assert } from '../utils/assert';
import { constants } from '../utils/constants';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ERC20ProxyWrapper } from './erc20_proxy_wrapper';
-import { ERC20TokenContract, ERC20TokenEventArgs, ERC20TokenEvents } from './generated/erc20_token';
-
-const removeUndefinedProperties = _.pickBy;
/**
* This class includes all the functionality related to interacting with ERC20 token contracts.
@@ -30,10 +29,17 @@ const removeUndefinedProperties = _.pickBy;
* to the 0x ERC20 Proxy smart contract.
*/
export class ERC20TokenWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.ERC20Token.compilerOutput.abi;
+ public abi: ContractAbi = ERC20Token.compilerOutput.abi;
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- private _tokenContractsByAddress: { [address: string]: ERC20TokenContract };
- private _erc20ProxyWrapper: ERC20ProxyWrapper;
+ private readonly _tokenContractsByAddress: { [address: string]: ERC20TokenContract };
+ private readonly _erc20ProxyWrapper: ERC20ProxyWrapper;
+ /**
+ * Instantiate ERC20TokenWrapper
+ * @param web3Wrapper Web3Wrapper instance to use
+ * @param networkId Desired networkId
+ * @param erc20ProxyWrapper The ERC20ProxyWrapper instance to use
+ * @param blockPollingIntervalMs The block polling interval to use for active subscriptions
+ */
constructor(
web3Wrapper: Web3Wrapper,
networkId: number,
@@ -101,7 +107,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.approve.sendTransactionAsync(
normalizedSpenderAddress,
amountInBaseUnits,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedOwnerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
@@ -182,7 +188,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
ownerAddress: string,
methodOpts: MethodOpts = {},
): Promise<BigNumber> {
- const proxyAddress = this._erc20ProxyWrapper.getContractAddress();
+ const proxyAddress = this._erc20ProxyWrapper.address;
const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts);
return allowanceInBaseUnits;
}
@@ -202,7 +208,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {},
): Promise<string> {
- const proxyAddress = this._erc20ProxyWrapper.getContractAddress();
+ const proxyAddress = this._erc20ProxyWrapper.address;
const txHash = await this.setAllowanceAsync(
tokenAddress,
ownerAddress,
@@ -271,7 +277,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.transfer.sendTransactionAsync(
normalizedToAddress,
amountInBaseUnits,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedFromAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
@@ -332,7 +338,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
normalizedFromAddress,
normalizedToAddress,
amountInBaseUnits,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedSenderAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
@@ -366,7 +372,7 @@ export class ERC20TokenWrapper extends ContractWrapper {
normalizedTokenAddress,
eventName,
indexFilterValues,
- artifacts.ERC20Token.compilerOutput.abi,
+ ERC20Token.compilerOutput.abi,
callback,
isVerbose,
);
@@ -411,30 +417,19 @@ export class ERC20TokenWrapper extends ContractWrapper {
eventName,
blockRange,
indexFilterValues,
- artifacts.ERC20Token.compilerOutput.abi,
+ ERC20Token.compilerOutput.abi,
);
return logs;
}
- // HACK: We don't want this method to be visible to the other units within that package but not to the end user.
- // TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
- // tslint:disable-next-line:no-unused-variable
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- this._tokenContractsByAddress = {};
- }
private async _getTokenContractAsync(tokenAddress: string): Promise<ERC20TokenContract> {
const normalizedTokenAddress = tokenAddress.toLowerCase();
let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
if (!_.isUndefined(tokenContract)) {
return tokenContract;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.ERC20Token,
- normalizedTokenAddress,
- );
const contractInstance = new ERC20TokenContract(
- abi,
- address,
+ this.abi,
+ normalizedTokenAddress,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts
index 38ecd4687..12758e191 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts
@@ -1,31 +1,42 @@
-import { AssetProxyId } from '@0xproject/types';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ERC721ProxyContract } from '@0x/abi-gen-wrappers';
+import { ERC721Proxy } from '@0x/contract-artifacts';
+import { AssetProxyId } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
import { assert } from '../utils/assert';
+import { _getDefaultContractAddresses } from '../utils/contract_addresses';
import { ContractWrapper } from './contract_wrapper';
-import { ERC721ProxyContract } from './generated/erc721_proxy';
/**
* This class includes the functionality related to interacting with the ERC721Proxy contract.
*/
export class ERC721ProxyWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.ERC20Proxy.compilerOutput.abi;
+ public abi: ContractAbi = ERC721Proxy.compilerOutput.abi;
+ public address: string;
private _erc721ProxyContractIfExists?: ERC721ProxyContract;
- private _contractAddressIfExists?: string;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
+ /**
+ * Instantiate ERC721ProxyWrapper
+ * @param web3Wrapper Web3Wrapper instance to use
+ * @param networkId Desired networkId
+ * @param address The address of the ERC721Proxy contract. If undefined,
+ * will default to the known address corresponding to the networkId.
+ */
+ constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) {
super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
+ this.address = _.isUndefined(address) ? _getDefaultContractAddresses(networkId).erc721Proxy : address;
}
/**
* Get the 4 bytes ID of this asset proxy
* @return Proxy id
*/
public async getProxyIdAsync(): Promise<AssetProxyId> {
- const ERC721ProxyContractInstance = await this._getERC721ProxyContractAsync();
+ const ERC721ProxyContractInstance = await this._getERC721ProxyContract();
+ // Note(albrow): Below is a TSLint false positive. Code won't compile if
+ // you remove the type assertion.
+ /* tslint:disable-next-line:no-unnecessary-type-assertion */
const proxyId = (await ERC721ProxyContractInstance.getProxyId.callAsync()) as AssetProxyId;
return proxyId;
}
@@ -37,7 +48,7 @@ export class ERC721ProxyWrapper extends ContractWrapper {
public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress);
const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase();
- const ERC721ProxyContractInstance = await this._getERC721ProxyContractAsync();
+ const ERC721ProxyContractInstance = await this._getERC721ProxyContract();
const isAuthorized = await ERC721ProxyContractInstance.authorized.callAsync(normalizedExchangeContractAddress);
return isAuthorized;
}
@@ -46,36 +57,17 @@ export class ERC721ProxyWrapper extends ContractWrapper {
* @return The list of authorized addresses.
*/
public async getAuthorizedAddressesAsync(): Promise<string[]> {
- const ERC721ProxyContractInstance = await this._getERC721ProxyContractAsync();
+ const ERC721ProxyContractInstance = await this._getERC721ProxyContract();
const authorizedAddresses = await ERC721ProxyContractInstance.getAuthorizedAddresses.callAsync();
return authorizedAddresses;
}
- /**
- * Retrieves the Ethereum address of the ERC721Proxy contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the ERC721Proxy contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ERC721Proxy, this._contractAddressIfExists);
- return contractAddress;
- }
- // HACK: We don't want this method to be visible to the other units within that package but not to the end user.
- // TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
- // tslint:disable-next-line:no-unused-variable
- private _invalidateContractInstance(): void {
- delete this._erc721ProxyContractIfExists;
- }
- private async _getERC721ProxyContractAsync(): Promise<ERC721ProxyContract> {
+ private _getERC721ProxyContract(): ERC721ProxyContract {
if (!_.isUndefined(this._erc721ProxyContractIfExists)) {
return this._erc721ProxyContractIfExists;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.ERC721Proxy,
- this._contractAddressIfExists,
- );
const contractInstance = new ERC721ProxyContract(
- abi,
- address,
+ this.abi,
+ this.address,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts
index 7231e0bde..1610af47b 100644
--- a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts
@@ -1,10 +1,11 @@
-import { schemas } from '@0xproject/json-schemas';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ERC721TokenContract, ERC721TokenEventArgs, ERC721TokenEvents } from '@0x/abi-gen-wrappers';
+import { ERC721Token } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
import { methodOptsSchema } from '../schemas/method_opts_schema';
import { txOptsSchema } from '../schemas/tx_opts_schema';
import {
@@ -17,12 +18,10 @@ import {
} from '../types';
import { assert } from '../utils/assert';
import { constants } from '../utils/constants';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ERC721ProxyWrapper } from './erc721_proxy_wrapper';
-import { ERC721TokenContract, ERC721TokenEventArgs, ERC721TokenEvents } from './generated/erc721_token';
-
-const removeUndefinedProperties = _.pickBy;
/**
* This class includes all the functionality related to interacting with ERC721 token contracts.
@@ -30,9 +29,16 @@ const removeUndefinedProperties = _.pickBy;
* to the 0x ERC721 Proxy smart contract.
*/
export class ERC721TokenWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.ERC721Token.compilerOutput.abi;
- private _tokenContractsByAddress: { [address: string]: ERC721TokenContract };
- private _erc721ProxyWrapper: ERC721ProxyWrapper;
+ public abi: ContractAbi = ERC721Token.compilerOutput.abi;
+ private readonly _tokenContractsByAddress: { [address: string]: ERC721TokenContract };
+ private readonly _erc721ProxyWrapper: ERC721ProxyWrapper;
+ /**
+ * Instantiate ERC721TokenWrapper
+ * @param web3Wrapper Web3Wrapper instance to use
+ * @param networkId Desired networkId
+ * @param erc721ProxyWrapper The ERC721ProxyWrapper instance to use
+ * @param blockPollingIntervalMs The block polling interval to use for active subscriptions
+ */
constructor(
web3Wrapper: Web3Wrapper,
networkId: number,
@@ -143,7 +149,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
ownerAddress: string,
methodOpts: MethodOpts = {},
): Promise<boolean> {
- const proxyAddress = this._erc721ProxyWrapper.getContractAddress();
+ const proxyAddress = this._erc721ProxyWrapper.address;
const isProxyApprovedForAll = await this.isApprovedForAllAsync(
tokenAddress,
ownerAddress,
@@ -192,7 +198,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
tokenId: BigNumber,
methodOpts: MethodOpts = {},
): Promise<boolean> {
- const proxyAddress = this._erc721ProxyWrapper.getContractAddress();
+ const proxyAddress = this._erc721ProxyWrapper.address;
const approvedAddress = await this.getApprovedIfExistsAsync(tokenAddress, tokenId, methodOpts);
const isProxyApproved = approvedAddress === proxyAddress;
return isProxyApproved;
@@ -228,7 +234,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.setApprovalForAll.sendTransactionAsync(
normalizedOperatorAddress,
isApproved,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
from: normalizedOwnerAddress,
@@ -253,7 +259,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
isApproved: boolean,
txOpts: TransactionOpts = {},
): Promise<string> {
- const proxyAddress = this._erc721ProxyWrapper.getContractAddress();
+ const proxyAddress = this._erc721ProxyWrapper.address;
const txHash = await this.setApprovalForAllAsync(tokenAddress, ownerAddress, proxyAddress, isApproved, txOpts);
return txHash;
}
@@ -288,7 +294,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.approve.sendTransactionAsync(
normalizedApprovedAddress,
tokenId,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
from: tokenOwnerAddress,
@@ -311,7 +317,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
tokenId: BigNumber,
txOpts: TransactionOpts = {},
): Promise<string> {
- const proxyAddress = this._erc721ProxyWrapper.getContractAddress();
+ const proxyAddress = this._erc721ProxyWrapper.address;
const txHash = await this.setApprovalAsync(tokenAddress, proxyAddress, tokenId, txOpts);
return txHash;
}
@@ -359,7 +365,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
ownerAddress,
normalizedReceiverAddress,
tokenId,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
from: normalizedSenderAddress,
@@ -393,7 +399,7 @@ export class ERC721TokenWrapper extends ContractWrapper {
normalizedTokenAddress,
eventName,
indexFilterValues,
- artifacts.ERC721Token.compilerOutput.abi,
+ ERC721Token.compilerOutput.abi,
callback,
isVerbose,
);
@@ -438,30 +444,19 @@ export class ERC721TokenWrapper extends ContractWrapper {
eventName,
blockRange,
indexFilterValues,
- artifacts.ERC721Token.compilerOutput.abi,
+ ERC721Token.compilerOutput.abi,
);
return logs;
}
- // HACK: We don't want this method to be visible to the other units within that package but not to the end user.
- // TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
- // tslint:disable-next-line:no-unused-variable
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- this._tokenContractsByAddress = {};
- }
private async _getTokenContractAsync(tokenAddress: string): Promise<ERC721TokenContract> {
const normalizedTokenAddress = tokenAddress.toLowerCase();
let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
if (!_.isUndefined(tokenContract)) {
return tokenContract;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.ERC721Token,
- normalizedTokenAddress,
- );
const contractInstance = new ERC721TokenContract(
- abi,
- address,
+ this.abi,
+ normalizedTokenAddress,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts
index 5046d3667..913c47cf7 100644
--- a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts
@@ -1,29 +1,35 @@
-import { schemas } from '@0xproject/json-schemas';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { WETH9Contract, WETH9EventArgs, WETH9Events } from '@0x/abi-gen-wrappers';
+import { WETH9 } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
import { BlockRange, ContractWrappersError, EventCallback, IndexedFilterValues, TransactionOpts } from '../types';
import { assert } from '../utils/assert';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ERC20TokenWrapper } from './erc20_token_wrapper';
-import { WETH9Contract, WETH9EventArgs, WETH9Events } from './generated/weth9';
-
-const removeUndefinedProperties = _.pickBy;
/**
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
*/
export class EtherTokenWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.EtherToken.compilerOutput.abi;
- private _etherTokenContractsByAddress: {
+ public abi: ContractAbi = WETH9.compilerOutput.abi;
+ private readonly _etherTokenContractsByAddress: {
[address: string]: WETH9Contract;
} = {};
- private _erc20TokenWrapper: ERC20TokenWrapper;
+ private readonly _erc20TokenWrapper: ERC20TokenWrapper;
+ /**
+ * Instantiate EtherTokenWrapper.
+ * @param web3Wrapper Web3Wrapper instance to use
+ * @param networkId Desired networkId
+ * @param erc20TokenWrapper The ERC20TokenWrapper instance to use
+ * @param blockPollingIntervalMs The block polling interval to use for active subscriptions
+ */
constructor(
web3Wrapper: Web3Wrapper,
networkId: number,
@@ -60,7 +66,7 @@ export class EtherTokenWrapper extends ContractWrapper {
const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
const txHash = await wethContract.deposit.sendTransactionAsync(
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedDepositorAddress,
value: amountInWei,
gas: txOpts.gasLimit,
@@ -102,7 +108,7 @@ export class EtherTokenWrapper extends ContractWrapper {
const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
const txHash = await wethContract.withdraw.sendTransactionAsync(
amountInWei,
- removeUndefinedProperties({
+ utils.removeUndefinedProperties({
from: normalizedWithdrawerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
@@ -135,7 +141,7 @@ export class EtherTokenWrapper extends ContractWrapper {
eventName,
blockRange,
indexFilterValues,
- artifacts.EtherToken.compilerOutput.abi,
+ WETH9.compilerOutput.abi,
);
return logs;
}
@@ -165,7 +171,7 @@ export class EtherTokenWrapper extends ContractWrapper {
normalizedEtherTokenAddress,
eventName,
indexFilterValues,
- artifacts.EtherToken.compilerOutput.abi,
+ WETH9.compilerOutput.abi,
callback,
isVerbose,
);
@@ -185,36 +191,14 @@ export class EtherTokenWrapper extends ContractWrapper {
public unsubscribeAll(): void {
super._unsubscribeAll();
}
- /**
- * Retrieves the Ethereum address of the EtherToken contract deployed on the network
- * that the user-passed web3 provider is connected to. If it's not Kovan, Ropsten, Rinkeby, Mainnet or TestRPC
- * (networkId: 50), it will return undefined (e.g a private network).
- * @returns The Ethereum address of the EtherToken contract or undefined.
- */
- public getContractAddressIfExists(): string | undefined {
- const networkSpecificArtifact = artifacts.EtherToken.networks[this._networkId];
- const contractAddressIfExists = _.isUndefined(networkSpecificArtifact)
- ? undefined
- : networkSpecificArtifact.address;
- return contractAddressIfExists;
- }
- // tslint:disable-next-line:no-unused-variable
- private _invalidateContractInstance(): void {
- this.unsubscribeAll();
- this._etherTokenContractsByAddress = {};
- }
private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<WETH9Contract> {
let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress];
if (!_.isUndefined(etherTokenContract)) {
return etherTokenContract;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.EtherToken,
- etherTokenAddress,
- );
const contractInstance = new WETH9Contract(
- abi,
- address,
+ this.abi,
+ etherTokenAddress,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
index 5a4b40547..2e978f35b 100644
--- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts
@@ -1,12 +1,20 @@
-import { schemas } from '@0xproject/json-schemas';
-import { assetDataUtils } from '@0xproject/order-utils';
-import { AssetProxyId, Order, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
+import { ExchangeContract, ExchangeEventArgs, ExchangeEvents } from '@0x/abi-gen-wrappers';
+import { Exchange } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import {
+ assetDataUtils,
+ BalanceAndProxyAllowanceLazyStore,
+ ExchangeTransferSimulator,
+ OrderValidationUtils,
+} from '@0x/order-utils';
+import { AssetProxyId, Order, SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { BlockParamLiteral, ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
+import { AssetBalanceAndProxyAllowanceFetcher } from '../fetchers/asset_balance_and_proxy_allowance_fetcher';
+import { OrderFilledCancelledFetcher } from '../fetchers/order_filled_cancelled_fetcher';
import { methodOptsSchema } from '../schemas/method_opts_schema';
import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
import { txOptsSchema } from '../schemas/tx_opts_schema';
@@ -18,33 +26,57 @@ import {
MethodOpts,
OrderInfo,
OrderTransactionOpts,
+ ValidateOrderFillableOpts,
} from '../types';
import { assert } from '../utils/assert';
+import { _getDefaultContractAddresses } from '../utils/contract_addresses';
import { decorators } from '../utils/decorators';
import { TransactionEncoder } from '../utils/transaction_encoder';
import { ContractWrapper } from './contract_wrapper';
-import { ExchangeContract, ExchangeEventArgs, ExchangeEvents } from './generated/exchange';
+import { ERC20TokenWrapper } from './erc20_token_wrapper';
+import { ERC721TokenWrapper } from './erc721_token_wrapper';
/**
* This class includes all the functionality related to calling methods, sending transactions and subscribing to
* events of the 0x V2 Exchange smart contract.
*/
export class ExchangeWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.Exchange.compilerOutput.abi;
+ public abi: ContractAbi = Exchange.compilerOutput.abi;
+ public address: string;
+ public zrxTokenAddress: string;
private _exchangeContractIfExists?: ExchangeContract;
- private _contractAddressIfExists?: string;
- private _zrxContractAddressIfExists?: string;
+ private readonly _erc721TokenWrapper: ERC721TokenWrapper;
+ private readonly _erc20TokenWrapper: ERC20TokenWrapper;
+ /**
+ * Instantiate ExchangeWrapper
+ * @param web3Wrapper Web3Wrapper instance to use.
+ * @param networkId Desired networkId.
+ * @param erc20TokenWrapper ERC20TokenWrapper instance to use.
+ * @param erc721TokenWrapper ERC721TokenWrapper instance to use.
+ * @param address The address of the Exchange contract. If undefined, will
+ * default to the known address corresponding to the networkId.
+ * @param zrxTokenAddress The address of the ZRXToken contract. If
+ * undefined, will default to the known address corresponding to the
+ * networkId.
+ * @param blockPollingIntervalMs The block polling interval to use for active subscriptions.
+ */
constructor(
web3Wrapper: Web3Wrapper,
networkId: number,
- contractAddressIfExists?: string,
- zrxContractAddressIfExists?: string,
+ erc20TokenWrapper: ERC20TokenWrapper,
+ erc721TokenWrapper: ERC721TokenWrapper,
+ address?: string,
+ zrxTokenAddress?: string,
blockPollingIntervalMs?: number,
) {
super(web3Wrapper, networkId, blockPollingIntervalMs);
- this._contractAddressIfExists = contractAddressIfExists;
- this._zrxContractAddressIfExists = zrxContractAddressIfExists;
+ this._erc20TokenWrapper = erc20TokenWrapper;
+ this._erc721TokenWrapper = erc721TokenWrapper;
+ this.address = _.isUndefined(address) ? _getDefaultContractAddresses(networkId).exchange : address;
+ this.zrxTokenAddress = _.isUndefined(zrxTokenAddress)
+ ? _getDefaultContractAddresses(networkId).zrxToken
+ : zrxTokenAddress;
}
/**
* Retrieve the address of an asset proxy by signature.
@@ -666,6 +698,7 @@ export class ExchangeWrapper extends ContractWrapper {
* @param leftSignedOrder First order to match.
* @param rightSignedOrder Second order to match.
* @param takerAddress The address that sends the transaction and gets the spread.
+ * @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
@@ -724,6 +757,7 @@ export class ExchangeWrapper extends ContractWrapper {
* @param signerAddress Address that should have signed the given hash.
* @param signature Proof that the hash has been signed by signer.
* @param senderAddress Address that should send the transaction.
+ * @param orderTransactionOpts Optional arguments this method accepts.
* @returns Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
@@ -902,7 +936,7 @@ export class ExchangeWrapper extends ContractWrapper {
/**
* Cancel a given order.
* @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel.
- * @param transactionOpts Optional arguments this method accepts.
+ * @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
@@ -1022,12 +1056,11 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
- const exchangeContractAddress = this.getContractAddress();
const subscriptionToken = this._subscribe<ArgsType>(
- exchangeContractAddress,
+ this.address,
eventName,
indexFilterValues,
- artifacts.Exchange.compilerOutput.abi,
+ Exchange.compilerOutput.abi,
callback,
isVerbose,
);
@@ -1062,40 +1095,79 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const exchangeContractAddress = this.getContractAddress();
const logs = await this._getLogsAsync<ArgsType>(
- exchangeContractAddress,
+ this.address,
eventName,
blockRange,
indexFilterValues,
- artifacts.Exchange.compilerOutput.abi,
+ Exchange.compilerOutput.abi,
);
return logs;
}
/**
- * Retrieves the Ethereum address of the Exchange contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the Exchange contract being used.
+ * Validate if the supplied order is fillable, and throw if it isn't
+ * @param signedOrder SignedOrder of interest
+ * @param opts ValidateOrderFillableOpts options (e.g expectedFillTakerTokenAmount.
+ * If it isn't supplied, we check if the order is fillable for a non-zero amount)
*/
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.Exchange, this._contractAddressIfExists);
- return contractAddress;
+ public async validateOrderFillableOrThrowAsync(
+ signedOrder: SignedOrder,
+ opts: ValidateOrderFillableOpts = {},
+ ): Promise<void> {
+ const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
+ this._erc20TokenWrapper,
+ this._erc721TokenWrapper,
+ BlockParamLiteral.Latest,
+ );
+ const balanceAllowanceStore = new BalanceAndProxyAllowanceLazyStore(balanceAllowanceFetcher);
+ const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore);
+
+ const expectedFillTakerTokenAmountIfExists = opts.expectedFillTakerTokenAmount;
+ const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest);
+ const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher);
+ await orderValidationUtils.validateOrderFillableOrThrowAsync(
+ exchangeTradeSimulator,
+ signedOrder,
+ this.getZRXAssetData(),
+ expectedFillTakerTokenAmountIfExists,
+ );
}
/**
- * Returns the ZRX token address used by the exchange contract.
- * @return Address of ZRX token
+ * Validate a call to FillOrder and throw if it wouldn't succeed
+ * @param signedOrder SignedOrder of interest
+ * @param fillTakerAssetAmount Amount we'd like to fill the order for
+ * @param takerAddress The taker of the order
*/
- public getZRXTokenAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ZRXToken, this._zrxContractAddressIfExists);
- return contractAddress;
+ public async validateFillOrderThrowIfInvalidAsync(
+ signedOrder: SignedOrder,
+ fillTakerAssetAmount: BigNumber,
+ takerAddress: string,
+ ): Promise<void> {
+ const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
+ this._erc20TokenWrapper,
+ this._erc721TokenWrapper,
+ BlockParamLiteral.Latest,
+ );
+ const balanceAllowanceStore = new BalanceAndProxyAllowanceLazyStore(balanceAllowanceFetcher);
+ const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore);
+
+ const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest);
+ const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher);
+ await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
+ exchangeTradeSimulator,
+ this._web3Wrapper.getProvider(),
+ signedOrder,
+ fillTakerAssetAmount,
+ takerAddress,
+ this.getZRXAssetData(),
+ );
}
/**
* Returns the ZRX asset data used by the exchange contract.
* @return ZRX asset data
*/
public getZRXAssetData(): string {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenAddress);
+ const zrxAssetData = assetDataUtils.encodeERC20AssetData(this.zrxTokenAddress);
return zrxAssetData;
}
/**
@@ -1108,23 +1180,14 @@ export class ExchangeWrapper extends ContractWrapper {
const encoder = new TransactionEncoder(exchangeInstance);
return encoder;
}
- // tslint:disable:no-unused-variable
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- delete this._exchangeContractIfExists;
- }
// tslint:enable:no-unused-variable
private async _getExchangeContractAsync(): Promise<ExchangeContract> {
if (!_.isUndefined(this._exchangeContractIfExists)) {
return this._exchangeContractIfExists;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.Exchange,
- this._contractAddressIfExists,
- );
const contractInstance = new ExchangeContract(
- abi,
- address,
+ this.abi,
+ this.address,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
index 13ef0fe01..80742e030 100644
--- a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
+++ b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
@@ -1,101 +1,145 @@
-import { schemas } from '@0xproject/json-schemas';
-import { AssetProxyId, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ForwarderContract } from '@0x/abi-gen-wrappers';
+import { Forwarder } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { ContractAbi } from 'ethereum-types';
import * as _ from 'lodash';
-import { artifacts } from '../artifacts';
import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
import { txOptsSchema } from '../schemas/tx_opts_schema';
-import { TransactionOpts } from '../types';
+import { OrderTransactionOpts } from '../types';
import { assert } from '../utils/assert';
import { calldataOptimizationUtils } from '../utils/calldata_optimization_utils';
import { constants } from '../utils/constants';
+import { _getDefaultContractAddresses } from '../utils/contract_addresses';
+import { decorators } from '../utils/decorators';
+import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
-import { ForwarderContract } from './generated/forwarder';
/**
* This class includes the functionality related to interacting with the Forwarder contract.
*/
export class ForwarderWrapper extends ContractWrapper {
- public abi: ContractAbi = artifacts.Forwarder.compilerOutput.abi;
+ public abi: ContractAbi = Forwarder.compilerOutput.abi;
+ public address: string;
+ public zrxTokenAddress: string;
+ public etherTokenAddress: string;
private _forwarderContractIfExists?: ForwarderContract;
- private _contractAddressIfExists?: string;
- private _zrxContractAddressIfExists?: string;
+
+ /**
+ * Instantiate ForwarderWrapper
+ * @param web3Wrapper Web3Wrapper instance to use.
+ * @param networkId Desired networkId.
+ * @param address The address of the Exchange contract. If undefined, will
+ * default to the known address corresponding to the networkId.
+ * @param zrxTokenAddress The address of the ZRXToken contract. If
+ * undefined, will default to the known address corresponding to the
+ * networkId.
+ * @param etherTokenAddress The address of a WETH (Ether token) contract. If
+ * undefined, will default to the known address corresponding to the
+ * networkId.
+ */
constructor(
web3Wrapper: Web3Wrapper,
networkId: number,
- contractAddressIfExists?: string,
- zrxContractAddressIfExists?: string,
+ address?: string,
+ zrxTokenAddress?: string,
+ etherTokenAddress?: string,
) {
super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
- this._zrxContractAddressIfExists = zrxContractAddressIfExists;
+ this.address = _.isUndefined(address) ? _getDefaultContractAddresses(networkId).exchange : address;
+ this.zrxTokenAddress = _.isUndefined(zrxTokenAddress)
+ ? _getDefaultContractAddresses(networkId).zrxToken
+ : zrxTokenAddress;
+ this.etherTokenAddress = _.isUndefined(etherTokenAddress)
+ ? _getDefaultContractAddresses(networkId).etherToken
+ : etherTokenAddress;
}
/**
* Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
* Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
* 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
* Any ETH not spent will be refunded to sender.
- * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
- * All orders must specify WETH as the takerAsset
- * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
- * Provider provided at instantiation.
- * @param ethAmount The amount of eth to send with the transaction (in wei).
- * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
- * Used to purchase ZRX for primary order fees.
- * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- * Defaults to 0.
- * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
- * @param txOpts Transaction parameters.
+ * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
+ * All orders must specify WETH as the takerAsset
+ * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
+ * Provider provided at instantiation.
+ * @param ethAmount The amount of eth to send with the transaction (in wei).
+ * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
+ * Used to purchase ZRX for primary order fees.
+ * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
+ * Defaults to 0.
+ * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
+ * @param orderTransactionOpts Transaction parameters.
* @return Transaction hash.
*/
+ @decorators.asyncZeroExErrorHandler
public async marketSellOrdersWithEthAsync(
signedOrders: SignedOrder[],
takerAddress: string,
ethAmount: BigNumber,
signedFeeOrders: SignedOrder[] = [],
- feePercentage: BigNumber = constants.ZERO_AMOUNT,
+ feePercentage: number = 0,
feeRecipientAddress: string = constants.NULL_ADDRESS,
- txOpts: TransactionOpts = {},
+ orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true },
): Promise<string> {
// type assertions
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.isBigNumber('ethAmount', ethAmount);
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
- assert.isBigNumber('feePercentage', feePercentage);
+ assert.isNumber('feePercentage', feePercentage);
assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
- assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
+ assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]);
// other assertions
- assert.ordersCanBeUsedForForwarderContract(signedOrders, this.getEtherTokenAddress());
- assert.feeOrdersCanBeUsedForForwarderContract(
- signedFeeOrders,
- this.getZRXTokenAddress(),
- this.getEtherTokenAddress(),
- );
+ assert.ordersCanBeUsedForForwarderContract(signedOrders, this.etherTokenAddress);
+ assert.feeOrdersCanBeUsedForForwarderContract(signedFeeOrders, this.zrxTokenAddress, this.etherTokenAddress);
+ // format feePercentage
+ const formattedFeePercentage = utils.numberPercentageToEtherTokenAmountPercentage(feePercentage);
// lowercase input addresses
const normalizedTakerAddress = takerAddress.toLowerCase();
const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
// optimize orders
const optimizedMarketOrders = calldataOptimizationUtils.optimizeForwarderOrders(signedOrders);
const optimizedFeeOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(signedFeeOrders);
- // send transaction
+ // compile signatures
+ const signatures = _.map(optimizedMarketOrders, order => order.signature);
+ const feeSignatures = _.map(optimizedFeeOrders, order => order.signature);
+ // get contract
const forwarderContractInstance = await this._getForwarderContractAsync();
+ // validate transaction
+ if (orderTransactionOpts.shouldValidate) {
+ await forwarderContractInstance.marketSellOrdersWithEth.callAsync(
+ optimizedMarketOrders,
+ signatures,
+ optimizedFeeOrders,
+ feeSignatures,
+ formattedFeePercentage,
+ normalizedFeeRecipientAddress,
+ {
+ value: ethAmount,
+ from: normalizedTakerAddress,
+ gas: orderTransactionOpts.gasLimit,
+ gasPrice: orderTransactionOpts.gasPrice,
+ },
+ );
+ }
+ // send transaction
const txHash = await forwarderContractInstance.marketSellOrdersWithEth.sendTransactionAsync(
optimizedMarketOrders,
- _.map(optimizedMarketOrders, order => order.signature),
+ signatures,
optimizedFeeOrders,
- _.map(optimizedFeeOrders, order => order.signature),
- feePercentage,
+ feeSignatures,
+ formattedFeePercentage,
feeRecipientAddress,
{
value: ethAmount,
from: normalizedTakerAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
+ gas: orderTransactionOpts.gasLimit,
+ gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -104,29 +148,30 @@ export class ForwarderWrapper extends ContractWrapper {
* Attempt to purchase makerAssetFillAmount of makerAsset by selling ethAmount provided with transaction.
* Any ZRX required to pay fees for primary orders will automatically be purchased by the contract.
* Any ETH not spent will be refunded to sender.
- * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
- * All orders must specify WETH as the takerAsset
- * @param makerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
- * Provider provided at instantiation.
- * @param ethAmount The amount of eth to send with the transaction (in wei).
- * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
- * Used to purchase ZRX for primary order fees.
- * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- * Defaults to 0.
- * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
- * @param txOpts Transaction parameters.
+ * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
+ * All orders must specify WETH as the takerAsset
+ * @param makerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill.
+ * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
+ * Provider provided at instantiation.
+ * @param ethAmount The amount of eth to send with the transaction (in wei).
+ * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
+ * Used to purchase ZRX for primary order fees.
+ * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
+ * Defaults to 0.
+ * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
+ * @param orderTransactionOpts Transaction parameters.
* @return Transaction hash.
*/
+ @decorators.asyncZeroExErrorHandler
public async marketBuyOrdersWithEthAsync(
signedOrders: SignedOrder[],
makerAssetFillAmount: BigNumber,
takerAddress: string,
ethAmount: BigNumber,
signedFeeOrders: SignedOrder[] = [],
- feePercentage: BigNumber = constants.ZERO_AMOUNT,
+ feePercentage: number = 0,
feeRecipientAddress: string = constants.NULL_ADDRESS,
- txOpts: TransactionOpts = {},
+ orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true },
): Promise<string> {
// type assertions
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
@@ -134,83 +179,68 @@ export class ForwarderWrapper extends ContractWrapper {
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.isBigNumber('ethAmount', ethAmount);
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
- assert.isBigNumber('feePercentage', feePercentage);
+ assert.isNumber('feePercentage', feePercentage);
assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
- assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
+ assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]);
// other assertions
- assert.ordersCanBeUsedForForwarderContract(signedOrders, this.getEtherTokenAddress());
- assert.feeOrdersCanBeUsedForForwarderContract(
- signedFeeOrders,
- this.getZRXTokenAddress(),
- this.getEtherTokenAddress(),
- );
+ assert.ordersCanBeUsedForForwarderContract(signedOrders, this.etherTokenAddress);
+ assert.feeOrdersCanBeUsedForForwarderContract(signedFeeOrders, this.zrxTokenAddress, this.etherTokenAddress);
+ // format feePercentage
+ const formattedFeePercentage = utils.numberPercentageToEtherTokenAmountPercentage(feePercentage);
// lowercase input addresses
const normalizedTakerAddress = takerAddress.toLowerCase();
const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
// optimize orders
const optimizedMarketOrders = calldataOptimizationUtils.optimizeForwarderOrders(signedOrders);
const optimizedFeeOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(signedFeeOrders);
- // send transaction
+ // compile signatures
+ const signatures = _.map(optimizedMarketOrders, order => order.signature);
+ const feeSignatures = _.map(optimizedFeeOrders, order => order.signature);
+ // get contract
const forwarderContractInstance = await this._getForwarderContractAsync();
+ // validate transaction
+ if (orderTransactionOpts.shouldValidate) {
+ await forwarderContractInstance.marketBuyOrdersWithEth.callAsync(
+ optimizedMarketOrders,
+ makerAssetFillAmount,
+ signatures,
+ optimizedFeeOrders,
+ feeSignatures,
+ formattedFeePercentage,
+ normalizedFeeRecipientAddress,
+ {
+ value: ethAmount,
+ from: normalizedTakerAddress,
+ gas: orderTransactionOpts.gasLimit,
+ gasPrice: orderTransactionOpts.gasPrice,
+ },
+ );
+ }
+ // send transaction
const txHash = await forwarderContractInstance.marketBuyOrdersWithEth.sendTransactionAsync(
optimizedMarketOrders,
makerAssetFillAmount,
- _.map(optimizedMarketOrders, order => order.signature),
+ signatures,
optimizedFeeOrders,
- _.map(optimizedFeeOrders, order => order.signature),
- feePercentage,
+ feeSignatures,
+ formattedFeePercentage,
feeRecipientAddress,
{
value: ethAmount,
from: normalizedTakerAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
+ gas: orderTransactionOpts.gasLimit,
+ gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
- /**
- * Retrieves the Ethereum address of the Forwarder contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the Forwarder contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.Forwarder, this._contractAddressIfExists);
- return contractAddress;
- }
- /**
- * Returns the ZRX token address used by the forwarder contract.
- * @return Address of ZRX token
- */
- public getZRXTokenAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ZRXToken, this._zrxContractAddressIfExists);
- return contractAddress;
- }
- /**
- * Returns the Ether token address used by the forwarder contract.
- * @return Address of Ether token
- */
- public getEtherTokenAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.EtherToken);
- return contractAddress;
- }
- // HACK: We don't want this method to be visible to the other units within that package but not to the end user.
- // TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
- // tslint:disable-next-line:no-unused-variable
- private _invalidateContractInstance(): void {
- delete this._forwarderContractIfExists;
- }
private async _getForwarderContractAsync(): Promise<ForwarderContract> {
if (!_.isUndefined(this._forwarderContractIfExists)) {
return this._forwarderContractIfExists;
}
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.Forwarder,
- this._contractAddressIfExists,
- );
const contractInstance = new ForwarderContract(
- abi,
- address,
+ this.abi,
+ this.address,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
diff --git a/packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts
new file mode 100644
index 000000000..c186e080e
--- /dev/null
+++ b/packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts
@@ -0,0 +1,185 @@
+import { OrderValidatorContract } from '@0x/abi-gen-wrappers';
+import { OrderValidator } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { ContractAbi } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { BalanceAndAllowance, OrderAndTraderInfo, TraderInfo } from '../types';
+import { assert } from '../utils/assert';
+import { _getDefaultContractAddresses } from '../utils/contract_addresses';
+
+import { ContractWrapper } from './contract_wrapper';
+
+/**
+ * This class includes the functionality related to interacting with the OrderValidator contract.
+ */
+export class OrderValidatorWrapper extends ContractWrapper {
+ public abi: ContractAbi = OrderValidator.compilerOutput.abi;
+ public address: string;
+ private _orderValidatorContractIfExists?: OrderValidatorContract;
+ /**
+ * Instantiate OrderValidatorWrapper
+ * @param web3Wrapper Web3Wrapper instance to use.
+ * @param networkId Desired networkId.
+ * @param address The address of the OrderValidator contract. If undefined,
+ * will default to the known address corresponding to the networkId.
+ */
+ constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) {
+ super(web3Wrapper, networkId);
+ this.address = _.isUndefined(address) ? _getDefaultContractAddresses(networkId).exchange : address;
+ }
+ /**
+ * Get an object conforming to OrderAndTraderInfo containing on-chain information of the provided order and address
+ * @param order An object conforming to SignedOrder
+ * @param takerAddress An ethereum address
+ * @return OrderAndTraderInfo
+ */
+ public async getOrderAndTraderInfoAsync(order: SignedOrder, takerAddress: string): Promise<OrderAndTraderInfo> {
+ assert.doesConformToSchema('order', order, schemas.signedOrderSchema);
+ assert.isETHAddressHex('takerAddress', takerAddress);
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const orderAndTraderInfo = await OrderValidatorContractInstance.getOrderAndTraderInfo.callAsync(
+ order,
+ takerAddress,
+ );
+ const result = {
+ orderInfo: orderAndTraderInfo[0],
+ traderInfo: orderAndTraderInfo[1],
+ };
+ return result;
+ }
+ /**
+ * Get an array of objects conforming to OrderAndTraderInfo containing on-chain information of the provided orders and addresses
+ * @param orders An array of objects conforming to SignedOrder
+ * @param takerAddresses An array of ethereum addresses
+ * @return array of OrderAndTraderInfo
+ */
+ public async getOrdersAndTradersInfoAsync(
+ orders: SignedOrder[],
+ takerAddresses: string[],
+ ): Promise<OrderAndTraderInfo[]> {
+ assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
+ _.forEach(takerAddresses, (takerAddress, index) =>
+ assert.isETHAddressHex(`takerAddresses[${index}]`, takerAddress),
+ );
+ assert.assert(orders.length === takerAddresses.length, 'Expected orders.length to equal takerAddresses.length');
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const ordersAndTradersInfo = await OrderValidatorContractInstance.getOrdersAndTradersInfo.callAsync(
+ orders,
+ takerAddresses,
+ );
+ const orderInfos = ordersAndTradersInfo[0];
+ const traderInfos = ordersAndTradersInfo[1];
+ const result = _.map(orderInfos, (orderInfo, index) => {
+ const traderInfo = traderInfos[index];
+ return {
+ orderInfo,
+ traderInfo,
+ };
+ });
+ return result;
+ }
+ /**
+ * Get an object conforming to TraderInfo containing on-chain balance and allowances for maker and taker of order
+ * @param order An object conforming to SignedOrder
+ * @param takerAddress An ethereum address
+ * @return TraderInfo
+ */
+ public async getTraderInfoAsync(order: SignedOrder, takerAddress: string): Promise<TraderInfo> {
+ assert.doesConformToSchema('order', order, schemas.signedOrderSchema);
+ assert.isETHAddressHex('takerAddress', takerAddress);
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const result = await OrderValidatorContractInstance.getTraderInfo.callAsync(order, takerAddress);
+ return result;
+ }
+ /**
+ * Get an array of objects conforming to TraderInfo containing on-chain balance and allowances for maker and taker of order
+ * @param orders An array of objects conforming to SignedOrder
+ * @param takerAddresses An array of ethereum addresses
+ * @return array of TraderInfo
+ */
+ public async getTradersInfoAsync(orders: SignedOrder[], takerAddresses: string[]): Promise<TraderInfo[]> {
+ assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
+ _.forEach(takerAddresses, (takerAddress, index) =>
+ assert.isETHAddressHex(`takerAddresses[${index}]`, takerAddress),
+ );
+ assert.assert(orders.length === takerAddresses.length, 'Expected orders.length to equal takerAddresses.length');
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const result = await OrderValidatorContractInstance.getTradersInfo.callAsync(orders, takerAddresses);
+ return result;
+ }
+ /**
+ * Get an object conforming to BalanceAndAllowance containing on-chain balance and allowance for some address and assetData
+ * @param address An ethereum address
+ * @param assetData An encoded string that can be decoded by a specified proxy contract
+ * @return BalanceAndAllowance
+ */
+ public async getBalanceAndAllowanceAsync(address: string, assetData: string): Promise<BalanceAndAllowance> {
+ assert.isETHAddressHex('address', address);
+ assert.isHexString('assetData', assetData);
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const balanceAndAllowance = await OrderValidatorContractInstance.getBalanceAndAllowance.callAsync(
+ address,
+ assetData,
+ );
+ const result = {
+ balance: balanceAndAllowance[0],
+ allowance: balanceAndAllowance[1],
+ };
+ return result;
+ }
+ /**
+ * Get an array of objects conforming to BalanceAndAllowance containing on-chain balance and allowance for some address and array of assetDatas
+ * @param address An ethereum address
+ * @param assetDatas An array of encoded strings that can be decoded by a specified proxy contract
+ * @return BalanceAndAllowance
+ */
+ public async getBalancesAndAllowancesAsync(address: string, assetDatas: string[]): Promise<BalanceAndAllowance[]> {
+ assert.isETHAddressHex('address', address);
+ _.forEach(assetDatas, (assetData, index) => assert.isHexString(`assetDatas[${index}]`, assetData));
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const balancesAndAllowances = await OrderValidatorContractInstance.getBalancesAndAllowances.callAsync(
+ address,
+ assetDatas,
+ );
+ const balances = balancesAndAllowances[0];
+ const allowances = balancesAndAllowances[1];
+ const result = _.map(balances, (balance, index) => {
+ const allowance = allowances[index];
+ return {
+ balance,
+ allowance,
+ };
+ });
+ return result;
+ }
+ /**
+ * Get owner address of tokenId by calling `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
+ * @param tokenAddress An ethereum address
+ * @param tokenId An ERC721 tokenId
+ * @return Owner of tokenId or null address if unowned
+ */
+ public async getERC721TokenOwnerAsync(tokenAddress: string, tokenId: BigNumber): Promise<string | undefined> {
+ assert.isETHAddressHex('tokenAddress', tokenAddress);
+ assert.isBigNumber('tokenId', tokenId);
+ const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
+ const result = await OrderValidatorContractInstance.getERC721TokenOwner.callAsync(tokenAddress, tokenId);
+ return result;
+ }
+ private async _getOrderValidatorContractAsync(): Promise<OrderValidatorContract> {
+ if (!_.isUndefined(this._orderValidatorContractIfExists)) {
+ return this._orderValidatorContractIfExists;
+ }
+ const contractInstance = new OrderValidatorContract(
+ this.abi,
+ this.address,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ this._orderValidatorContractIfExists = contractInstance;
+ return this._orderValidatorContractIfExists;
+ }
+}
diff --git a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts
new file mode 100644
index 000000000..d10cffe57
--- /dev/null
+++ b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts
@@ -0,0 +1,77 @@
+// tslint:disable:no-unnecessary-type-assertion
+import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils';
+import { AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { BlockParamLiteral } from 'ethereum-types';
+
+import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper';
+import { ERC721TokenWrapper } from '../contract_wrappers/erc721_token_wrapper';
+
+export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher {
+ private readonly _erc20Token: ERC20TokenWrapper;
+ private readonly _erc721Token: ERC721TokenWrapper;
+ private readonly _stateLayer: BlockParamLiteral;
+ constructor(erc20Token: ERC20TokenWrapper, erc721Token: ERC721TokenWrapper, stateLayer: BlockParamLiteral) {
+ this._erc20Token = erc20Token;
+ this._erc721Token = erc721Token;
+ this._stateLayer = stateLayer;
+ }
+ public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
+ const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
+ const balance = await this._erc20Token.getBalanceAsync(decodedERC20AssetData.tokenAddress, userAddress, {
+ defaultBlock: this._stateLayer,
+ });
+ return balance;
+ } else {
+ const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
+ const tokenOwner = await this._erc721Token.getOwnerOfAsync(
+ decodedERC721AssetData.tokenAddress,
+ decodedERC721AssetData.tokenId,
+ {
+ defaultBlock: this._stateLayer,
+ },
+ );
+ const balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
+ return balance;
+ }
+ }
+ public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
+ const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
+ const proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(
+ decodedERC20AssetData.tokenAddress,
+ userAddress,
+ {
+ defaultBlock: this._stateLayer,
+ },
+ );
+ return proxyAllowance;
+ } else {
+ const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
+
+ const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync(
+ decodedERC721AssetData.tokenAddress,
+ userAddress,
+ {
+ defaultBlock: this._stateLayer,
+ },
+ );
+ if (isApprovedForAll) {
+ return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
+ } else {
+ const isApproved = await this._erc721Token.isProxyApprovedAsync(
+ decodedERC721AssetData.tokenAddress,
+ decodedERC721AssetData.tokenId,
+ {
+ defaultBlock: this._stateLayer,
+ },
+ );
+ const proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
+ return proxyAllowance;
+ }
+ }
+ }
+}
diff --git a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts
new file mode 100644
index 000000000..acf7038fa
--- /dev/null
+++ b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts
@@ -0,0 +1,29 @@
+// tslint:disable:no-unnecessary-type-assertion
+import { AbstractOrderFilledCancelledFetcher } from '@0x/order-utils';
+import { BigNumber } from '@0x/utils';
+import { BlockParamLiteral } from 'ethereum-types';
+
+import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
+
+export class OrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher {
+ private readonly _exchange: ExchangeWrapper;
+ private readonly _stateLayer: BlockParamLiteral;
+ constructor(exchange: ExchangeWrapper, stateLayer: BlockParamLiteral) {
+ this._exchange = exchange;
+ this._stateLayer = stateLayer;
+ }
+ public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
+ const filledTakerAmount = this._exchange.getFilledTakerAssetAmountAsync(orderHash, {
+ defaultBlock: this._stateLayer,
+ });
+ return filledTakerAmount;
+ }
+ public async isOrderCancelledAsync(orderHash: string): Promise<boolean> {
+ const isCancelled = await this._exchange.isCancelledAsync(orderHash);
+ return isCancelled;
+ }
+ public getZRXAssetData(): string {
+ const zrxAssetData = this._exchange.getZRXAssetData();
+ return zrxAssetData;
+ }
+}
diff --git a/packages/contract-wrappers/src/globals.d.ts b/packages/contract-wrappers/src/globals.d.ts
deleted file mode 100644
index 94e63a32d..000000000
--- a/packages/contract-wrappers/src/globals.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-declare module '*.json' {
- const json: any;
- /* tslint:disable */
- export default json;
- /* tslint:enable */
-}
diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts
index 1986e0004..d66ff5c9c 100644
--- a/packages/contract-wrappers/src/index.ts
+++ b/packages/contract-wrappers/src/index.ts
@@ -1,3 +1,30 @@
+export { ContractAddresses } from '@0x/contract-addresses';
+
+export {
+ WETH9Events,
+ WETH9WithdrawalEventArgs,
+ WETH9ApprovalEventArgs,
+ WETH9EventArgs,
+ WETH9DepositEventArgs,
+ WETH9TransferEventArgs,
+ ERC20TokenTransferEventArgs,
+ ERC20TokenApprovalEventArgs,
+ ERC20TokenEvents,
+ ERC20TokenEventArgs,
+ ERC721TokenApprovalEventArgs,
+ ERC721TokenApprovalForAllEventArgs,
+ ERC721TokenTransferEventArgs,
+ ERC721TokenEvents,
+ ERC721TokenEventArgs,
+ ExchangeCancelUpToEventArgs,
+ ExchangeAssetProxyRegisteredEventArgs,
+ ExchangeSignatureValidatorApprovalEventArgs,
+ ExchangeFillEventArgs,
+ ExchangeCancelEventArgs,
+ ExchangeEventArgs,
+ ExchangeEvents,
+} from '@0x/abi-gen-wrappers';
+
export { ContractWrappers } from './contract_wrappers';
export { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper';
export { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper';
@@ -6,77 +33,56 @@ export { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
+export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
+
+export { TransactionEncoder } from './utils/transaction_encoder';
export {
ContractWrappersError,
- EventCallback,
- ContractEvent,
- Token,
+ ForwarderWrapperError,
IndexedFilterValues,
BlockRange,
- OrderFillRequest,
- ContractEventArgs,
ContractWrappersConfig,
MethodOpts,
OrderTransactionOpts,
TransactionOpts,
- LogEvent,
- DecodedLogEvent,
- OnOrderStateChangeCallback,
OrderStatus,
OrderInfo,
+ EventCallback,
+ DecodedLogEvent,
+ BalanceAndAllowance,
+ OrderAndTraderInfo,
+ TraderInfo,
+ ValidateOrderFillableOpts,
} from './types';
-export {
- Order,
- SignedOrder,
- ECSignature,
- OrderStateValid,
- OrderStateInvalid,
- OrderState,
- AssetProxyId,
-} from '@0xproject/types';
+export { Order, SignedOrder, AssetProxyId } from '@0x/types';
export {
BlockParamLiteral,
- FilterObject,
BlockParam,
ContractEventArg,
- LogWithDecodedArgs,
Provider,
- TransactionReceipt,
- TransactionReceiptWithDecodedLogs,
+ ContractAbi,
+ JSONRPCRequestPayload,
+ JSONRPCResponsePayload,
+ JSONRPCErrorCallback,
+ JSONRPCResponseError,
+ AbiDefinition,
+ LogWithDecodedArgs,
+ FunctionAbi,
+ EventAbi,
+ EventParameter,
+ DecodedLogArgs,
+ MethodAbi,
+ ConstructorAbi,
+ FallbackAbi,
+ DataItem,
+ ConstructorStateMutability,
+ StateMutability,
} from 'ethereum-types';
-export {
- WETH9Events,
- WETH9WithdrawalEventArgs,
- WETH9ApprovalEventArgs,
- WETH9EventArgs,
- WETH9DepositEventArgs,
- WETH9TransferEventArgs,
-} from './contract_wrappers/generated/weth9';
-
-export {
- ERC20TokenTransferEventArgs,
- ERC20TokenApprovalEventArgs,
- ERC20TokenEvents,
- ERC20TokenEventArgs,
-} from './contract_wrappers/generated/erc20_token';
+export { AbstractBalanceAndProxyAllowanceFetcher, AbstractOrderFilledCancelledFetcher } from '@0x/order-utils';
-export {
- ERC721TokenApprovalEventArgs,
- ERC721TokenApprovalForAllEventArgs,
- ERC721TokenTransferEventArgs,
- ERC721TokenEvents,
- ERC721TokenEventArgs,
-} from './contract_wrappers/generated/erc721_token';
-
-export {
- ExchangeCancelUpToEventArgs,
- ExchangeAssetProxyRegisteredEventArgs,
- ExchangeFillEventArgs,
- ExchangeCancelEventArgs,
- ExchangeEventArgs,
- ExchangeEvents,
-} from './contract_wrappers/generated/exchange';
+export { AssetBalanceAndProxyAllowanceFetcher } from './fetchers/asset_balance_and_proxy_allowance_fetcher';
+export { OrderFilledCancelledFetcher } from './fetchers/order_filled_cancelled_fetcher';
diff --git a/packages/contract-wrappers/src/monorepo_scripts/postpublish.ts b/packages/contract-wrappers/src/monorepo_scripts/postpublish.ts
deleted file mode 100644
index dcb99d0f7..000000000
--- a/packages/contract-wrappers/src/monorepo_scripts/postpublish.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { postpublishUtils } from '@0xproject/monorepo-scripts';
-
-import * as packageJSON from '../package.json';
-import * as tsConfigJSON from '../tsconfig.json';
-
-const cwd = `${__dirname}/..`;
-// tslint:disable-next-line:no-floating-promises
-postpublishUtils.runAsync(packageJSON, tsConfigJSON, cwd);
diff --git a/packages/contract-wrappers/src/schemas/contract_wrappers_config_schema.ts b/packages/contract-wrappers/src/schemas/contract_wrappers_config_schema.ts
index ac248b2d4..ae1ce668c 100644
--- a/packages/contract-wrappers/src/schemas/contract_wrappers_config_schema.ts
+++ b/packages/contract-wrappers/src/schemas/contract_wrappers_config_schema.ts
@@ -1,5 +1,25 @@
export const ContractWrappersConfigSchema = {
id: '/ContractWrappersConfig',
- oneOf: [{ $ref: '/ZeroExContractPrivateNetworkConfig' }, { $ref: '/ZeroExContractPublicNetworkConfig' }],
+ properties: {
+ networkId: {
+ type: 'number',
+ },
+ gasPrice: { $ref: '/numberSchema' },
+ contractAddresses: {
+ type: 'object',
+ properties: {
+ erc20Proxy: { $ref: '/addressSchema' },
+ erc721Proxy: { $ref: '/addressSchema' },
+ zrxToken: { $ref: '/addressSchema' },
+ etherToken: { $ref: '/addressSchema' },
+ exchange: { $ref: '/addressSchema' },
+ assetProxyOwner: { $ref: '/addressSchema' },
+ forwarder: { $ref: '/addressSchema' },
+ orderValidator: { $ref: '/addressSchema' },
+ },
+ },
+ blockPollingIntervalMs: { type: 'number' },
+ },
type: 'object',
+ required: ['networkId'],
};
diff --git a/packages/contract-wrappers/src/schemas/contract_wrappers_private_network_config_schema.ts b/packages/contract-wrappers/src/schemas/contract_wrappers_private_network_config_schema.ts
deleted file mode 100644
index 904690ae7..000000000
--- a/packages/contract-wrappers/src/schemas/contract_wrappers_private_network_config_schema.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-export const contractWrappersPrivateNetworkConfigSchema = {
- id: '/ZeroExContractPrivateNetworkConfig',
- properties: {
- networkId: {
- type: 'number',
- minimum: 1,
- },
- gasPrice: { $ref: '/numberSchema' },
- zrxContractAddress: { $ref: '/addressSchema' },
- exchangeContractAddress: { $ref: '/addressSchema' },
- erc20ProxyContractAddress: { $ref: '/addressSchema' },
- erc721ProxyContractAddress: { $ref: '/addressSchema' },
- blockPollingIntervalMs: { type: 'number' },
- orderWatcherConfig: {
- type: 'object',
- properties: {
- pollingIntervalMs: {
- type: 'number',
- minimum: 0,
- },
- numConfirmations: {
- type: 'number',
- minimum: 0,
- },
- },
- },
- },
- type: 'object',
- required: [
- 'networkId',
- 'zrxContractAddress',
- 'exchangeContractAddress',
- 'erc20ProxyContractAddress',
- 'erc721ProxyContractAddress',
- ],
-};
diff --git a/packages/contract-wrappers/src/schemas/contract_wrappers_public_network_config_schema.ts b/packages/contract-wrappers/src/schemas/contract_wrappers_public_network_config_schema.ts
deleted file mode 100644
index 5cd008ae0..000000000
--- a/packages/contract-wrappers/src/schemas/contract_wrappers_public_network_config_schema.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-const networkNameToId: { [networkName: string]: number } = {
- mainnet: 1,
- ropsten: 3,
- rinkeby: 4,
- kovan: 42,
- ganache: 50,
-};
-
-export const contractWrappersPublicNetworkConfigSchema = {
- id: '/ZeroExContractPublicNetworkConfig',
- properties: {
- networkId: {
- type: 'number',
- enum: [
- networkNameToId.mainnet,
- networkNameToId.kovan,
- networkNameToId.ropsten,
- networkNameToId.rinkeby,
- networkNameToId.ganache,
- ],
- },
- gasPrice: { $ref: '/numberSchema' },
- zrxContractAddress: { $ref: '/addressSchema' },
- exchangeContractAddress: { $ref: '/addressSchema' },
- erc20ProxyContractAddress: { $ref: '/addressSchema' },
- erc721ProxyContractAddress: { $ref: '/addressSchema' },
- blockPollingIntervalMs: { type: 'number' },
- orderWatcherConfig: {
- type: 'object',
- properties: {
- pollingIntervalMs: {
- type: 'number',
- minimum: 0,
- },
- numConfirmations: {
- type: 'number',
- minimum: 0,
- },
- },
- },
- },
- type: 'object',
- required: ['networkId'],
-};
diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts
index 2b3cdc591..5a5bdd530 100644
--- a/packages/contract-wrappers/src/types.ts
+++ b/packages/contract-wrappers/src/types.ts
@@ -1,25 +1,28 @@
-import { BigNumber } from '@0xproject/utils';
+import {
+ ERC20TokenEventArgs,
+ ERC20TokenEvents,
+ ERC721TokenEventArgs,
+ ERC721TokenEvents,
+ ExchangeEventArgs,
+ ExchangeEvents,
+ WETH9EventArgs,
+ WETH9Events,
+} from '@0x/abi-gen-wrappers';
+import { ContractAddresses } from '@0x/contract-addresses';
+import { OrderState, SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
-import { OrderState, SignedOrder } from '@0xproject/types';
import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types';
-import { ERC20TokenEventArgs, ERC20TokenEvents } from './contract_wrappers/generated/erc20_token';
-import { ERC721TokenEventArgs, ERC721TokenEvents } from './contract_wrappers/generated/erc721_token';
-import { ExchangeEventArgs, ExchangeEvents } from './contract_wrappers/generated/exchange';
-import { WETH9EventArgs, WETH9Events } from './contract_wrappers/generated/weth9';
-
export enum ExchangeWrapperError {
AssetDataMismatch = 'ASSET_DATA_MISMATCH',
}
+export enum ForwarderWrapperError {
+ CompleteFillFailed = 'COMPLETE_FILL_FAILED',
+}
+
export enum ContractWrappersError {
- ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST',
- ZRXContractDoesNotExist = 'ZRX_CONTRACT_DOES_NOT_EXIST',
- EtherTokenContractDoesNotExist = 'ETHER_TOKEN_CONTRACT_DOES_NOT_EXIST',
- ERC20ProxyContractDoesNotExist = 'ERC20_PROXY_CONTRACT_DOES_NOT_EXIST',
- ERC721ProxyContractDoesNotExist = 'ERC721_PROXY_CONTRACT_DOES_NOT_EXIST',
- ERC20TokenContractDoesNotExist = 'ERC20_TOKEN_CONTRACT_DOES_NOT_EXIST',
- ERC721TokenContractDoesNotExist = 'ERC721_TOKEN_CONTRACT_DOES_NOT_EXIST',
ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK',
InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER',
InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER',
@@ -31,6 +34,7 @@ export enum ContractWrappersError {
SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT',
ERC721OwnerNotFound = 'ERC_721_OWNER_NOT_FOUND',
ERC721NoApproval = 'ERC_721_NO_APPROVAL',
+ SignatureRequestDenied = 'SIGNATURE_REQUEST_DENIED',
}
export enum InternalContractWrappersError {
@@ -105,22 +109,13 @@ export type SyncMethod = (...args: any[]) => any;
/**
* networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc)
* gasPrice: Gas price to use with every transaction
- * exchangeContractAddress: The address of an exchange contract to use
- * zrxContractAddress: The address of the ZRX contract to use
- * erc20ProxyContractAddress: The address of the erc20 token transfer proxy contract to use
- * erc721ProxyContractAddress: The address of the erc721 token transfer proxy contract to use
- * forwarderContractAddress: The address of the forwarder contract to use
- * orderWatcherConfig: All the configs related to the orderWatcher
+ * contractAddresses: The address of all contracts to use. Defaults to the known addresses based on networkId.
* blockPollingIntervalMs: The interval to use for block polling in event watching methods (defaults to 1000)
*/
export interface ContractWrappersConfig {
networkId: number;
gasPrice?: BigNumber;
- exchangeContractAddress?: string;
- zrxContractAddress?: string;
- erc20ProxyContractAddress?: string;
- erc721ProxyContractAddress?: string;
- forwarderContractAddress?: string;
+ contractAddresses?: ContractAddresses;
blockPollingIntervalMs?: number;
}
@@ -188,3 +183,24 @@ export enum OrderStatus {
FULLY_FILLED,
CANCELLED,
}
+
+export interface TraderInfo {
+ makerBalance: BigNumber;
+ makerAllowance: BigNumber;
+ takerBalance: BigNumber;
+ takerAllowance: BigNumber;
+ makerZrxBalance: BigNumber;
+ makerZrxAllowance: BigNumber;
+ takerZrxBalance: BigNumber;
+ takerZrxAllowance: BigNumber;
+}
+
+export interface OrderAndTraderInfo {
+ orderInfo: OrderInfo;
+ traderInfo: TraderInfo;
+}
+
+export interface BalanceAndAllowance {
+ balance: BigNumber;
+ allowance: BigNumber;
+}
diff --git a/packages/contract-wrappers/src/utils/assert.ts b/packages/contract-wrappers/src/utils/assert.ts
index 183642170..3f02ed052 100644
--- a/packages/contract-wrappers/src/utils/assert.ts
+++ b/packages/contract-wrappers/src/utils/assert.ts
@@ -1,10 +1,10 @@
-import { assert as sharedAssert } from '@0xproject/assert';
+import { assert as sharedAssert } from '@0x/assert';
// HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here
-import { Schema } from '@0xproject/json-schemas'; // tslint:disable-line:no-unused-variable
-import { assetDataUtils, isValidSignatureAsync } from '@0xproject/order-utils';
-import { ECSignature, Order } from '@0xproject/types'; // tslint:disable-line:no-unused-variable
-import { BigNumber } from '@0xproject/utils'; // tslint:disable-line:no-unused-variable
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { Schema } from '@0x/json-schemas'; // tslint:disable-line:no-unused-variable
+import { assetDataUtils, signatureUtils } from '@0x/order-utils';
+import { Order } from '@0x/types'; // tslint:disable-line:no-unused-variable
+import { BigNumber } from '@0x/utils'; // tslint:disable-line:no-unused-variable
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
@@ -18,7 +18,7 @@ export const assert = {
signature: string,
signerAddress: string,
): Promise<void> {
- const isValid = await isValidSignatureAsync(provider, orderHash, signature, signerAddress);
+ const isValid = await signatureUtils.isValidSignatureAsync(provider, orderHash, signature, signerAddress);
sharedAssert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
},
isValidSubscriptionToken(variableName: string, subscriptionToken: string): void {
diff --git a/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts b/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts
index 3172cf531..bee7acaa7 100644
--- a/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts
+++ b/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts
@@ -1,4 +1,4 @@
-import { SignedOrder } from '@0xproject/types';
+import { SignedOrder } from '@0x/types';
import * as _ from 'lodash';
import { constants } from './constants';
diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts
index 2df11538c..c587ba526 100644
--- a/packages/contract-wrappers/src/utils/constants.ts
+++ b/packages/contract-wrappers/src/utils/constants.ts
@@ -1,4 +1,4 @@
-import { BigNumber } from '@0xproject/utils';
+import { BigNumber } from '@0x/utils';
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
@@ -12,4 +12,7 @@ export const constants = {
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
ZERO_AMOUNT: new BigNumber(0),
+ ONE_AMOUNT: new BigNumber(1),
+ ETHER_TOKEN_DECIMALS: 18,
+ USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature',
};
diff --git a/packages/contract-wrappers/src/utils/contract_addresses.ts b/packages/contract-wrappers/src/utils/contract_addresses.ts
new file mode 100644
index 000000000..dc156e017
--- /dev/null
+++ b/packages/contract-wrappers/src/utils/contract_addresses.ts
@@ -0,0 +1,15 @@
+import { ContractAddresses, getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses';
+import * as _ from 'lodash';
+
+/**
+ * Returns the default contract addresses for the given networkId or throws with
+ * a context-specific error message if the networkId is not recognized.
+ */
+export function _getDefaultContractAddresses(networkId: number): ContractAddresses {
+ if (!(networkId in NetworkId)) {
+ throw new Error(
+ `No default contract addresses found for the given network id (${networkId}). If you want to use ContractWrappers on this network, you must manually pass in the contract address(es) to the constructor.`,
+ );
+ }
+ return getContractAddressesForNetworkOrThrow(networkId);
+}
diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts
index 6e77450e8..a4207ae4c 100644
--- a/packages/contract-wrappers/src/utils/decorators.ts
+++ b/packages/contract-wrappers/src/utils/decorators.ts
@@ -1,4 +1,3 @@
-import { RevertReason } from '@0xproject/types';
import * as _ from 'lodash';
import { AsyncMethod, ContractWrappersError, SyncMethod } from '../types';
@@ -24,7 +23,15 @@ const contractCallErrorTransformer = (error: Error) => {
const schemaErrorTransformer = (error: Error) => {
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
const errMsg =
- 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
+ 'Order taker must be of type string. If you want anyone to be able to fill an order - pass NULL_ADDRESS';
+ return new Error(errMsg);
+ }
+ return error;
+};
+
+const signatureRequestErrorTransformer = (error: Error) => {
+ if (_.includes(error.message, constants.USER_DENIED_SIGNATURE_PATTERN)) {
+ const errMsg = ContractWrappersError.SignatureRequestDenied;
return new Error(errMsg);
}
return error;
@@ -46,7 +53,7 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
// tslint:disable-next-line:only-arrow-functions
descriptor.value = async function(...args: any[]): Promise<any> {
try {
- const result = await originalMethod.apply(this, args);
+ const result = await originalMethod.apply(this, args); // tslint:disable-line:no-invalid-this
return result;
} catch (error) {
const transformedError = errorTransformer(error);
@@ -73,7 +80,7 @@ const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
// tslint:disable-next-line:only-arrow-functions
descriptor.value = function(...args: any[]): any {
try {
- const result = originalMethod.apply(this, args);
+ const result = originalMethod.apply(this, args); // tslint:disable-line:no-invalid-this
return result;
} catch (error) {
const transformedError = errorTransformer(error);
@@ -88,7 +95,11 @@ const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
};
// _.flow(f, g) = f ∘ g
-const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer);
+const zeroExErrorTransformer = _.flow(
+ schemaErrorTransformer,
+ contractCallErrorTransformer,
+ signatureRequestErrorTransformer,
+);
export const decorators = {
asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer),
diff --git a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts
index 279f2a796..f374d509b 100644
--- a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts
+++ b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts
@@ -1,5 +1,5 @@
-import { ExchangeContractErrs } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { ExchangeContractErrs } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
import { TradeSide, TransferType } from '../types';
@@ -34,7 +34,7 @@ const ERR_MSG_MAPPING = {
};
export class ExchangeTransferSimulator {
- private _store: AbstractBalanceAndProxyAllowanceLazyStore;
+ private readonly _store: AbstractBalanceAndProxyAllowanceLazyStore;
private static _throwValidationError(
failureReason: FailureReason,
tradeSide: TradeSide,
diff --git a/packages/contract-wrappers/src/utils/filter_utils.ts b/packages/contract-wrappers/src/utils/filter_utils.ts
index 0e73987f7..c05be062c 100644
--- a/packages/contract-wrappers/src/utils/filter_utils.ts
+++ b/packages/contract-wrappers/src/utils/filter_utils.ts
@@ -1,4 +1,4 @@
-import { ConstructorAbi, ContractAbi, EventAbi, FallbackAbi, FilterObject, LogEntry, MethodAbi } from 'ethereum-types';
+import { ContractAbi, EventAbi, FilterObject, LogEntry } from 'ethereum-types';
import * as ethUtil from 'ethereumjs-util';
import * as jsSHA3 from 'js-sha3';
import * as _ from 'lodash';
diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts
index 5c2a94b74..0cf08a8fe 100644
--- a/packages/contract-wrappers/src/utils/transaction_encoder.ts
+++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts
@@ -1,29 +1,20 @@
-import { schemas } from '@0xproject/json-schemas';
-import { EIP712Schema, EIP712Types, EIP712Utils } from '@0xproject/order-utils';
-import { Order, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import _ = require('lodash');
+import { ExchangeContract } from '@0x/abi-gen-wrappers';
-import { ExchangeContract } from '../contract_wrappers/generated/exchange';
+import { schemas } from '@0x/json-schemas';
+import { eip712Utils } from '@0x/order-utils';
+import { Order, SignedOrder } from '@0x/types';
+import { BigNumber, signTypedDataUtils } from '@0x/utils';
+import _ = require('lodash');
import { assert } from './assert';
-const EIP712_ZEROEX_TRANSACTION_SCHEMA: EIP712Schema = {
- name: 'ZeroExTransaction',
- parameters: [
- { name: 'salt', type: EIP712Types.Uint256 },
- { name: 'signerAddress', type: EIP712Types.Address },
- { name: 'data', type: EIP712Types.Bytes },
- ],
-};
-
/**
* Transaction Encoder. Transaction messages exist for the purpose of calling methods on the Exchange contract
* in the context of another address. For example, UserA can encode and sign a fillOrder transaction and UserB
* can submit this to the blockchain. The Exchange context executes as if UserA had directly submitted this transaction.
*/
export class TransactionEncoder {
- private _exchangeInstance: ExchangeContract;
+ private readonly _exchangeInstance: ExchangeContract;
constructor(exchangeInstance: ExchangeContract) {
this._exchangeInstance = exchangeInstance;
}
@@ -41,12 +32,9 @@ export class TransactionEncoder {
signerAddress,
data,
};
- const executeTransactionHashBuff = EIP712Utils.structHash(
- EIP712_ZEROEX_TRANSACTION_SCHEMA,
- executeTransactionData,
- );
- const eip721MessageBuffer = EIP712Utils.createEIP712Message(executeTransactionHashBuff, exchangeAddress);
- const messageHex = `0x${eip721MessageBuffer.toString('hex')}`;
+ const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, exchangeAddress);
+ const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
+ const messageHex = `0x${eip712MessageBuffer.toString('hex')}`;
return messageHex;
}
/**
diff --git a/packages/contract-wrappers/src/utils/utils.ts b/packages/contract-wrappers/src/utils/utils.ts
index 689a7ee0a..0b3270e78 100644
--- a/packages/contract-wrappers/src/utils/utils.ts
+++ b/packages/contract-wrappers/src/utils/utils.ts
@@ -1,4 +1,8 @@
-import { BigNumber } from '@0xproject/utils';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as _ from 'lodash';
+
+import { constants } from './constants';
export const utils = {
getCurrentUnixTimestampSec(): BigNumber {
@@ -8,4 +12,10 @@ export const utils = {
getCurrentUnixTimestampMs(): BigNumber {
return new BigNumber(Date.now());
},
+ numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber {
+ return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).mul(percentage);
+ },
+ removeUndefinedProperties<T extends object>(obj: T): Partial<T> {
+ return _.pickBy(obj);
+ },
};
diff --git a/packages/contract-wrappers/test/artifacts_test.ts b/packages/contract-wrappers/test/artifacts_test.ts
deleted file mode 100644
index c05d513b3..000000000
--- a/packages/contract-wrappers/test/artifacts_test.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { web3Factory } from '@0xproject/dev-utils';
-
-import { ContractWrappers } from '../src';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-
-chaiSetup.configure();
-
-// Those tests are slower cause they're talking to a remote node
-const TIMEOUT = 10000;
-
-// TODO: Re-enable those tests after final kovan and ropsten deployments are done.
-describe.skip('Artifacts', () => {
- describe('contracts are deployed on kovan', () => {
- const kovanRpcUrl = constants.KOVAN_RPC_URL;
- const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
- const config = {
- networkId: constants.KOVAN_NETWORK_ID,
- };
- const contractWrappers = new ContractWrappers(provider, config);
- it('erc20 proxy contract is deployed', async () => {
- await (contractWrappers.erc20Proxy as any)._getTokenTransferProxyContractAsync();
- }).timeout(TIMEOUT);
- it('erc721 proxy contract is deployed', async () => {
- await (contractWrappers.erc721Proxy as any)._getTokenTransferProxyContractAsync();
- }).timeout(TIMEOUT);
- });
- describe('contracts are deployed on ropsten', () => {
- const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
- const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
- const config = {
- networkId: constants.ROPSTEN_NETWORK_ID,
- };
- const contractWrappers = new ContractWrappers(provider, config);
- it('erc20 proxy contract is deployed', async () => {
- await (contractWrappers.erc20Proxy as any)._getTokenTransferProxyContractAsync();
- }).timeout(TIMEOUT);
- it('erc721 proxy contract is deployed', async () => {
- await (contractWrappers.erc721Proxy as any)._getTokenTransferProxyContractAsync();
- }).timeout(TIMEOUT);
- });
-});
diff --git a/packages/contract-wrappers/test/calldata_optimization_utils_test.ts b/packages/contract-wrappers/test/calldata_optimization_utils_test.ts
index a4cea772f..6cb8a669e 100644
--- a/packages/contract-wrappers/test/calldata_optimization_utils_test.ts
+++ b/packages/contract-wrappers/test/calldata_optimization_utils_test.ts
@@ -1,9 +1,8 @@
-import { orderFactory } from '@0xproject/order-utils';
+import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
-import { assert } from '../src/utils/assert';
import { calldataOptimizationUtils } from '../src/utils/calldata_optimization_utils';
import { constants } from '../src/utils/constants';
diff --git a/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts b/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts
index 6bf9f1e25..d8dfa4204 100644
--- a/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts
+++ b/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts
@@ -4,6 +4,7 @@ import { ContractWrappers } from '../src';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { provider } from './utils/web3_wrapper';
chaiSetup.configure();
@@ -11,10 +12,13 @@ const expect = chai.expect;
describe('ERC20ProxyWrapper', () => {
let contractWrappers: ContractWrappers;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
contractWrappers = new ContractWrappers(provider, config);
});
describe('#isAuthorizedAsync', () => {
diff --git a/packages/contract-wrappers/test/erc20_wrapper_test.ts b/packages/contract-wrappers/test/erc20_wrapper_test.ts
index cf7ac527e..15d3a9ead 100644
--- a/packages/contract-wrappers/test/erc20_wrapper_test.ts
+++ b/packages/contract-wrappers/test/erc20_wrapper_test.ts
@@ -1,7 +1,8 @@
-import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
-import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0xproject/subproviders';
-import { DoneCallback } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { ContractAddresses } from '@0x/contract-addresses';
+import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
+import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0x/subproviders';
+import { DoneCallback } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { Provider } from 'ethereum-types';
import 'mocha';
@@ -10,6 +11,7 @@ import {
BlockParamLiteral,
BlockRange,
ContractWrappers,
+ ContractWrappersConfig,
ContractWrappersError,
DecodedLogEvent,
ERC20TokenApprovalEventArgs,
@@ -19,6 +21,7 @@ import {
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -28,14 +31,20 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('ERC20Wrapper', () => {
let contractWrappers: ContractWrappers;
+ let contractAddresses: ContractAddresses;
let userAddresses: string[];
let tokens: string[];
let coinbase: string;
let addressWithoutFunds: string;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
+ let config: ContractWrappersConfig;
+
before(async () => {
+ contractAddresses = await migrateOnceAsync();
+ config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
contractWrappers = new ContractWrappers(provider, config);
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
tokens = tokenUtils.getDummyERC20TokenAddresses();
@@ -71,19 +80,6 @@ describe('ERC20Wrapper', () => {
contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount),
).to.be.rejectedWith(ContractWrappersError.InsufficientBalanceForTransfer);
});
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- const fromAddress = coinbase;
- const toAddress = coinbase;
- return expect(
- contractWrappers.erc20Token.transferAsync(
- nonExistentTokenAddress,
- fromAddress,
- toAddress,
- transferAmount,
- ),
- ).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist);
- });
});
describe('#transferFromAsync', () => {
let tokenAddress: string;
@@ -188,19 +184,6 @@ describe('ERC20Wrapper', () => {
const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress);
return expect(postBalance).to.be.bignumber.equal(transferAmount);
});
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const fromAddress = coinbase;
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- return expect(
- contractWrappers.erc20Token.transferFromAsync(
- nonExistentTokenAddress,
- fromAddress,
- toAddress,
- senderAddress,
- new BigNumber(42),
- ),
- ).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist);
- });
});
describe('#getBalanceAsync', () => {
describe('With provider with accounts', () => {
@@ -211,13 +194,6 @@ describe('ERC20Wrapper', () => {
const expectedBalance = new BigNumber('1000000000000000000000000000');
return expect(balance).to.be.bignumber.equal(expectedBalance);
});
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- const ownerAddress = coinbase;
- return expect(
- contractWrappers.erc20Token.getBalanceAsync(nonExistentTokenAddress, ownerAddress),
- ).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist);
- });
it('should return a balance of 0 for a non-existent owner address', async () => {
const tokenAddress = tokens[0];
const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593';
@@ -293,7 +269,7 @@ describe('ERC20Wrapper', () => {
});
it('should reduce the gas cost for transfers including tokens with unlimited allowance support', async () => {
const transferAmount = new BigNumber(5);
- const zrxAddress = tokenUtils.getProtocolTokenAddress();
+ const zrxAddress = contractAddresses.zrxToken;
const [, userWithNormalAllowance, userWithUnlimitedAllowance] = userAddresses;
await contractWrappers.erc20Token.setAllowanceAsync(
zrxAddress,
@@ -524,7 +500,7 @@ describe('ERC20Wrapper', () => {
);
})().catch(done);
});
- it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => {
+ it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
(_logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => {
@@ -538,7 +514,7 @@ describe('ERC20Wrapper', () => {
callbackNeverToBeCalled,
);
const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)();
- contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID);
+ contractWrappers.unsubscribeAll();
contractWrappers.erc20Token.subscribe(
tokenAddress,
ERC20TokenEvents.Transfer,
@@ -587,7 +563,7 @@ describe('ERC20Wrapper', () => {
let txHash: string;
before(() => {
tokenAddress = tokens[0];
- tokenTransferProxyAddress = contractWrappers.erc20Proxy.getContractAddress();
+ tokenTransferProxyAddress = contractWrappers.erc20Proxy.address;
});
it('should get logs with decoded args emitted by Approval', async () => {
txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
diff --git a/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts b/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts
index 9473d930b..9b0fe8817 100644
--- a/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts
+++ b/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts
@@ -4,6 +4,7 @@ import { ContractWrappers } from '../src';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { provider } from './utils/web3_wrapper';
chaiSetup.configure();
@@ -11,10 +12,13 @@ const expect = chai.expect;
describe('ERC721ProxyWrapper', () => {
let contractWrappers: ContractWrappers;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
contractWrappers = new ContractWrappers(provider, config);
});
describe('#isAuthorizedAsync', () => {
diff --git a/packages/contract-wrappers/test/erc721_wrapper_test.ts b/packages/contract-wrappers/test/erc721_wrapper_test.ts
index f005ac2e0..a7f1e4c41 100644
--- a/packages/contract-wrappers/test/erc721_wrapper_test.ts
+++ b/packages/contract-wrappers/test/erc721_wrapper_test.ts
@@ -1,7 +1,7 @@
-import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
-import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0xproject/subproviders';
-import { DoneCallback } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
+import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0x/subproviders';
+import { DoneCallback } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { Provider } from 'ethereum-types';
import 'mocha';
@@ -10,6 +10,7 @@ import {
BlockParamLiteral,
BlockRange,
ContractWrappers,
+ ContractWrappersConfig,
ContractWrappersError,
DecodedLogEvent,
ERC721TokenApprovalEventArgs,
@@ -20,6 +21,7 @@ import {
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -37,10 +39,15 @@ describe('ERC721Wrapper', () => {
let operatorAddress: string;
let approvedAddress: string;
let receiverAddress: string;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
+ let config: ContractWrappersConfig;
+
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
+ config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
contractWrappers = new ContractWrappers(provider, config);
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
tokens = tokenUtils.getDummyERC721TokenAddresses();
@@ -108,12 +115,6 @@ describe('ERC721Wrapper', () => {
tokenCount = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, ownerAddress);
expect(tokenCount).to.be.bignumber.equal(1);
});
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- return expect(
- contractWrappers.erc721Token.getTokenCountAsync(nonExistentTokenAddress, ownerAddress),
- ).to.be.rejectedWith(ContractWrappersError.ERC721TokenContractDoesNotExist);
- });
it('should return a balance of 0 for a non-existent owner address', async () => {
const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593';
const balance = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, nonExistentOwner);
@@ -142,13 +143,6 @@ describe('ERC721Wrapper', () => {
const tokenOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId);
expect(tokenOwner).to.be.bignumber.equal(ownerAddress);
});
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- const fakeTokenId = new BigNumber(42);
- return expect(
- contractWrappers.erc721Token.getOwnerOfAsync(nonExistentTokenAddress, fakeTokenId),
- ).to.be.rejectedWith(ContractWrappersError.ERC721TokenContractDoesNotExist);
- });
it('should return undefined not 0 for a non-existent ERC721', async () => {
const fakeTokenId = new BigNumber(42);
return expect(contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, fakeTokenId)).to.be.rejectedWith(
@@ -229,11 +223,17 @@ describe('ERC721Wrapper', () => {
it('should set the proxy approval', async () => {
const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress);
- const approvalBeforeSet = await contractWrappers.erc721Token.isProxyApprovedAsync(tokenAddress, tokenId);
- expect(approvalBeforeSet).to.be.false();
+ const isProxyApprovedBeforeSet = await contractWrappers.erc721Token.isProxyApprovedAsync(
+ tokenAddress,
+ tokenId,
+ );
+ expect(isProxyApprovedBeforeSet).to.be.false();
await contractWrappers.erc721Token.setProxyApprovalAsync(tokenAddress, tokenId);
- const approvalAfterSet = await contractWrappers.erc721Token.isProxyApprovedAsync(tokenAddress, tokenId);
- expect(approvalAfterSet).to.be.true();
+ const isProxyApprovedAfterSet = await contractWrappers.erc721Token.isProxyApprovedAsync(
+ tokenAddress,
+ tokenId,
+ );
+ expect(isProxyApprovedAfterSet).to.be.true();
});
});
describe('#subscribe', () => {
@@ -313,7 +313,7 @@ describe('ERC721Wrapper', () => {
);
})().catch(done);
});
- it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => {
+ it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
(logEvent: DecodedLogEvent<ERC721TokenApprovalEventArgs>) => {
@@ -327,7 +327,7 @@ describe('ERC721Wrapper', () => {
callbackNeverToBeCalled,
);
const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)();
- contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID);
+ contractWrappers.unsubscribeAll();
contractWrappers.erc721Token.subscribe(
tokenAddress,
ERC721TokenEvents.Approval,
@@ -357,7 +357,6 @@ describe('ERC721Wrapper', () => {
);
contractWrappers.erc721Token.unsubscribe(subscriptionToken);
- const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress);
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await contractWrappers.erc721Token.setApprovalForAllAsync(
@@ -373,15 +372,11 @@ describe('ERC721Wrapper', () => {
});
});
describe('#getLogsAsync', () => {
- let tokenTransferProxyAddress: string;
const blockRange: BlockRange = {
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
let txHash: string;
- before(() => {
- tokenTransferProxyAddress = contractWrappers.erc721Proxy.getContractAddress();
- });
it('should get logs with decoded args emitted by ApprovalForAll', async () => {
const isApprovedForAll = true;
txHash = await contractWrappers.erc721Token.setApprovalForAllAsync(
diff --git a/packages/contract-wrappers/test/ether_token_wrapper_test.ts b/packages/contract-wrappers/test/ether_token_wrapper_test.ts
index 48bd6d3f6..e3efef19d 100644
--- a/packages/contract-wrappers/test/ether_token_wrapper_test.ts
+++ b/packages/contract-wrappers/test/ether_token_wrapper_test.ts
@@ -1,7 +1,8 @@
-import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
-import { DoneCallback } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ContractAddresses } from '@0x/contract-addresses';
+import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
+import { DoneCallback } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import 'mocha';
@@ -10,17 +11,17 @@ import {
BlockRange,
ContractWrappers,
ContractWrappersError,
- DecodedLogEvent,
WETH9ApprovalEventArgs,
WETH9DepositEventArgs,
WETH9Events,
WETH9TransferEventArgs,
WETH9WithdrawalEventArgs,
} from '../src';
+import { DecodedLogEvent } from '../src/types';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
-import { tokenUtils } from './utils/token_utils';
+import { migrateOnceAsync } from './utils/migrate';
import { provider, web3Wrapper } from './utils/web3_wrapper';
chaiSetup.configure();
@@ -35,6 +36,7 @@ const MAX_REASONABLE_GAS_COST_IN_WEI = 62517;
describe('EtherTokenWrapper', () => {
let contractWrappers: ContractWrappers;
+ let contractAddresses: ContractAddresses;
let userAddresses: string[];
let addressWithETH: string;
let wethContractAddress: string;
@@ -42,19 +44,22 @@ describe('EtherTokenWrapper', () => {
const decimalPlaces = 7;
let addressWithoutFunds: string;
const gasPrice = new BigNumber(1);
- const zeroExConfig = {
- gasPrice,
- networkId: constants.TESTRPC_NETWORK_ID,
- };
const transferAmount = new BigNumber(42);
const allowanceAmount = new BigNumber(42);
const depositAmount = new BigNumber(42);
const withdrawalAmount = new BigNumber(42);
before(async () => {
- contractWrappers = new ContractWrappers(provider, zeroExConfig);
+ contractAddresses = await migrateOnceAsync();
+ const config = {
+ gasPrice,
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
+ contractWrappers = new ContractWrappers(provider, config);
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
addressWithETH = userAddresses[0];
- wethContractAddress = contractWrappers.etherToken.getContractAddressIfExists() as string;
+ wethContractAddress = contractAddresses.etherToken;
depositWeiAmount = Web3Wrapper.toWei(new BigNumber(5));
addressWithoutFunds = userAddresses[1];
});
@@ -66,7 +71,7 @@ describe('EtherTokenWrapper', () => {
});
describe('#getContractAddressIfExists', async () => {
it('should return contract address if connected to a known network', () => {
- const contractAddressIfExists = contractWrappers.etherToken.getContractAddressIfExists();
+ const contractAddressIfExists = contractAddresses.etherToken;
expect(contractAddressIfExists).to.not.be.undefined();
});
it('should throw if connected to a private network and contract addresses are not specified', () => {
@@ -171,7 +176,7 @@ describe('EtherTokenWrapper', () => {
const indexFilterValues = {};
let etherTokenAddress: string;
before(async () => {
- etherTokenAddress = tokenUtils.getWethTokenAddress();
+ etherTokenAddress = contractAddresses.etherToken;
});
afterEach(() => {
contractWrappers.etherToken.unsubscribeAll();
@@ -278,7 +283,7 @@ describe('EtherTokenWrapper', () => {
await contractWrappers.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH);
})().catch(done);
});
- it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
+ it('should cancel outstanding subscriptions when contractWrappers.unsubscribeAll is called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
(_logEvent: DecodedLogEvent<WETH9ApprovalEventArgs>) => {
@@ -292,7 +297,7 @@ describe('EtherTokenWrapper', () => {
callbackNeverToBeCalled,
);
const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)();
- contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID);
+ contractWrappers.unsubscribeAll();
await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
contractWrappers.etherToken.subscribe(
etherTokenAddress,
@@ -340,10 +345,10 @@ describe('EtherTokenWrapper', () => {
let txHash: string;
before(async () => {
addressWithETH = userAddresses[0];
- etherTokenAddress = tokenUtils.getWethTokenAddress();
- erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress();
+ etherTokenAddress = contractAddresses.etherToken;
+ erc20ProxyAddress = contractWrappers.erc20Proxy.address;
// Start the block range after all migrations to avoid unexpected logs
- const currentBlock = await web3Wrapper.getBlockNumberAsync();
+ const currentBlock: number = await web3Wrapper.getBlockNumberAsync();
const fromBlock = currentBlock + 1;
blockRange = {
fromBlock,
diff --git a/packages/contract-wrappers/test/exchange_wrapper_test.ts b/packages/contract-wrappers/test/exchange_wrapper_test.ts
index fa3b49eb9..0e537bd83 100644
--- a/packages/contract-wrappers/test/exchange_wrapper_test.ts
+++ b/packages/contract-wrappers/test/exchange_wrapper_test.ts
@@ -1,23 +1,18 @@
-import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
-import { FillScenarios } from '@0xproject/fill-scenarios';
-import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
-import { DoneCallback, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
+import { FillScenarios } from '@0x/fill-scenarios';
+import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
+import { DoneCallback, SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { BlockParamLiteral } from 'ethereum-types';
import 'mocha';
-import {
- ContractWrappers,
- DecodedLogEvent,
- ExchangeCancelEventArgs,
- ExchangeEvents,
- ExchangeFillEventArgs,
- OrderStatus,
-} from '../src';
+import { ContractWrappers, ExchangeCancelEventArgs, ExchangeEvents, ExchangeFillEventArgs, OrderStatus } from '../src';
+import { DecodedLogEvent } from '../src/types';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -33,37 +28,38 @@ describe('ExchangeWrapper', () => {
let exchangeContractAddress: string;
let makerTokenAddress: string;
let takerTokenAddress: string;
- let coinbase: string;
let makerAddress: string;
let anotherMakerAddress: string;
let takerAddress: string;
let makerAssetData: string;
let takerAssetData: string;
- let feeRecipient: string;
let txHash: string;
const fillableAmount = new BigNumber(5);
const takerTokenFillAmount = new BigNumber(5);
let signedOrder: SignedOrder;
let anotherSignedOrder: SignedOrder;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- blockPollingIntervalMs: 0,
- };
+
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
await blockchainLifecycle.startAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
contractWrappers = new ContractWrappers(provider, config);
- exchangeContractAddress = contractWrappers.exchange.getContractAddress();
+ exchangeContractAddress = contractWrappers.exchange.address;
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- zrxTokenAddress = tokenUtils.getProtocolTokenAddress();
+ zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress;
fillScenarios = new FillScenarios(
provider,
userAddresses,
zrxTokenAddress,
exchangeContractAddress,
- contractWrappers.erc20Proxy.getContractAddress(),
- contractWrappers.erc721Proxy.getContractAddress(),
+ contractWrappers.erc20Proxy.address,
+ contractWrappers.erc721Proxy.address,
);
- [coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses;
+ [, makerAddress, takerAddress, , anotherMakerAddress] = userAddresses;
[makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
[makerAssetData, takerAssetData] = [
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
@@ -335,11 +331,11 @@ describe('ExchangeWrapper', () => {
it('should fill or kill a valid order', async () => {
const erc20ProxyId = await contractWrappers.erc20Proxy.getProxyIdAsync();
const erc20ProxyAddressById = await contractWrappers.exchange.getAssetProxyBySignatureAsync(erc20ProxyId);
- const erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress();
+ const erc20ProxyAddress = contractWrappers.erc20Proxy.address;
expect(erc20ProxyAddressById).to.be.equal(erc20ProxyAddress);
const erc721ProxyId = await contractWrappers.erc721Proxy.getProxyIdAsync();
const erc721ProxyAddressById = await contractWrappers.exchange.getAssetProxyBySignatureAsync(erc721ProxyId);
- const erc721ProxyAddress = contractWrappers.erc721Proxy.getContractAddress();
+ const erc721ProxyAddress = contractWrappers.erc721Proxy.address;
expect(erc721ProxyAddressById).to.be.equal(erc721ProxyAddress);
});
});
@@ -364,7 +360,7 @@ describe('ExchangeWrapper', () => {
describe('#getVersionAsync', () => {
it('should return version the hash', async () => {
const version = await contractWrappers.exchange.getVersionAsync();
- const VERSION = '2.0.1-alpha';
+ const VERSION = '2.0.0';
expect(version).to.be.equal(VERSION);
});
});
@@ -414,7 +410,7 @@ describe('ExchangeWrapper', () => {
await contractWrappers.exchange.cancelOrderAsync(signedOrder);
})().catch(done);
});
- it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => {
+ it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
(logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => {
@@ -423,7 +419,7 @@ describe('ExchangeWrapper', () => {
);
contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callbackNeverToBeCalled);
- contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID);
+ contractWrappers.unsubscribeAll();
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(
(logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => {
@@ -460,13 +456,6 @@ describe('ExchangeWrapper', () => {
})().catch(done);
});
});
- describe('#getZRXTokenAddressAsync', () => {
- it('gets the same token as is in token registry', () => {
- const zrxAddressFromExchangeWrapper = contractWrappers.exchange.getZRXTokenAddress();
- const zrxAddress = tokenUtils.getProtocolTokenAddress();
- expect(zrxAddressFromExchangeWrapper).to.equal(zrxAddress);
- });
- });
describe('#getLogsAsync', () => {
const blockRange = {
fromBlock: 0,
diff --git a/packages/contract-wrappers/test/forwarder_wrapper_test.ts b/packages/contract-wrappers/test/forwarder_wrapper_test.ts
index 3f3b40e0b..ff4ff8b67 100644
--- a/packages/contract-wrappers/test/forwarder_wrapper_test.ts
+++ b/packages/contract-wrappers/test/forwarder_wrapper_test.ts
@@ -1,23 +1,16 @@
-import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
-import { FillScenarios } from '@0xproject/fill-scenarios';
-import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
-import { DoneCallback, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { FillScenarios } from '@0x/fill-scenarios';
+import { assetDataUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
-import { BlockParamLiteral } from 'ethereum-types';
import 'mocha';
-import {
- ContractWrappers,
- DecodedLogEvent,
- ExchangeCancelEventArgs,
- ExchangeEvents,
- ExchangeFillEventArgs,
- OrderStatus,
-} from '../src';
+import { ContractWrappers, OrderStatus } from '../src';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -25,24 +18,16 @@ chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+// tslint:disable:custom-no-magic-numbers
describe('ForwarderWrapper', () => {
- const contractWrappersConfig = {
- networkId: constants.TESTRPC_NETWORK_ID,
- blockPollingIntervalMs: 0,
- };
const fillableAmount = new BigNumber(5);
- const takerTokenFillAmount = new BigNumber(5);
let contractWrappers: ContractWrappers;
let fillScenarios: FillScenarios;
- let forwarderContractAddress: string;
let exchangeContractAddress: string;
let zrxTokenAddress: string;
let userAddresses: string[];
- let coinbase: string;
let makerAddress: string;
let takerAddress: string;
- let feeRecipient: string;
- let anotherMakerAddress: string;
let makerTokenAddress: string;
let takerTokenAddress: string;
let makerAssetData: string;
@@ -50,23 +35,28 @@ describe('ForwarderWrapper', () => {
let signedOrder: SignedOrder;
let anotherSignedOrder: SignedOrder;
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
await blockchainLifecycle.startAsync();
- contractWrappers = new ContractWrappers(provider, contractWrappersConfig);
- forwarderContractAddress = contractWrappers.forwarder.getContractAddress();
- exchangeContractAddress = contractWrappers.exchange.getContractAddress();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
+ contractWrappers = new ContractWrappers(provider, config);
+ exchangeContractAddress = contractWrappers.exchange.address;
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- zrxTokenAddress = tokenUtils.getProtocolTokenAddress();
+ zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress;
fillScenarios = new FillScenarios(
provider,
userAddresses,
zrxTokenAddress,
exchangeContractAddress,
- contractWrappers.erc20Proxy.getContractAddress(),
- contractWrappers.erc721Proxy.getContractAddress(),
+ contractWrappers.erc20Proxy.address,
+ contractWrappers.erc721Proxy.address,
);
- [coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses;
+ [, makerAddress, takerAddress] = userAddresses;
[makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
- takerTokenAddress = tokenUtils.getWethTokenAddress();
+ takerTokenAddress = contractWrappers.forwarder.etherTokenAddress;
[makerAssetData, takerAssetData] = [
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
@@ -110,6 +100,25 @@ describe('ForwarderWrapper', () => {
expect(ordersInfo[0].orderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
expect(ordersInfo[1].orderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
});
+ it('should throw when invalid transaction and shouldValidate is true', async () => {
+ const signedOrders = [signedOrder];
+ // request more makerAsset than what is available
+ const makerAssetFillAmount = signedOrder.makerAssetAmount.plus(100);
+ return expect(
+ contractWrappers.forwarder.marketBuyOrdersWithEthAsync(
+ signedOrders,
+ makerAssetFillAmount,
+ takerAddress,
+ makerAssetFillAmount,
+ [],
+ 0,
+ constants.NULL_ADDRESS,
+ {
+ shouldValidate: true,
+ },
+ ),
+ ).to.be.rejectedWith('COMPLETE_FILL_FAILED');
+ });
});
describe('#marketSellOrdersWithEthAsync', () => {
it('should market sell orders with eth', async () => {
@@ -126,5 +135,33 @@ describe('ForwarderWrapper', () => {
expect(ordersInfo[1].orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(ordersInfo[1].orderTakerAssetFilledAmount).to.be.bignumber.equal(new BigNumber(4)); // only 95% of ETH is sold
});
+ it('should throw when invalid transaction and shouldValidate is true', async () => {
+ // create an order with fees, we try to fill it but we do not provide enough ETH to cover the fees
+ const signedOrderWithFee = await fillScenarios.createFillableSignedOrderWithFeesAsync(
+ makerAssetData,
+ takerAssetData,
+ constants.ZERO_AMOUNT,
+ new BigNumber(100),
+ makerAddress,
+ constants.NULL_ADDRESS,
+ fillableAmount,
+ constants.NULL_ADDRESS,
+ );
+ const signedOrders = [signedOrderWithFee];
+ const makerAssetFillAmount = signedOrder.makerAssetAmount;
+ return expect(
+ contractWrappers.forwarder.marketSellOrdersWithEthAsync(
+ signedOrders,
+ takerAddress,
+ makerAssetFillAmount,
+ [],
+ 0,
+ constants.NULL_ADDRESS,
+ {
+ shouldValidate: true,
+ },
+ ),
+ ).to.be.rejectedWith('COMPLETE_FILL_FAILED');
+ });
});
});
diff --git a/packages/contract-wrappers/test/global_hooks.ts b/packages/contract-wrappers/test/global_hooks.ts
index 8731318e7..e23739b59 100644
--- a/packages/contract-wrappers/test/global_hooks.ts
+++ b/packages/contract-wrappers/test/global_hooks.ts
@@ -1,17 +1,6 @@
-import { devConstants } from '@0xproject/dev-utils';
-import { runV2MigrationsAsync } from '@0xproject/migrations';
-
-import { provider } from './utils/web3_wrapper';
-
-before('migrate contracts', async function(): Promise<void> {
+before('set up mocha', async function(): Promise<void> {
// HACK: Since the migrations take longer then our global mocha timeout limit
// we manually increase it for this before hook.
const mochaTestTimeoutMs = 50000;
this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this
- const txDefaults = {
- gas: devConstants.GAS_LIMIT,
- from: devConstants.TESTRPC_FIRST_ADDRESS,
- };
- const artifactsDir = `src/artifacts`;
- await runV2MigrationsAsync(provider, artifactsDir, txDefaults);
});
diff --git a/packages/contract-wrappers/test/order_validator_wrapper_test.ts b/packages/contract-wrappers/test/order_validator_wrapper_test.ts
new file mode 100644
index 000000000..da3f99e72
--- /dev/null
+++ b/packages/contract-wrappers/test/order_validator_wrapper_test.ts
@@ -0,0 +1,146 @@
+import { ContractAddresses } from '@0x/contract-addresses';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { FillScenarios } from '@0x/fill-scenarios';
+import { assetDataUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import * as chai from 'chai';
+import * as _ from 'lodash';
+import 'mocha';
+
+import { ContractWrappers, OrderStatus } from '../src';
+import { OrderInfo, TraderInfo } from '../src/types';
+
+import { chaiSetup } from './utils/chai_setup';
+import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
+import { tokenUtils } from './utils/token_utils';
+import { provider, web3Wrapper } from './utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+
+describe('OrderValidator', () => {
+ const fillableAmount = new BigNumber(5);
+ let contractWrappers: ContractWrappers;
+ let fillScenarios: FillScenarios;
+ let exchangeContractAddress: string;
+ let zrxTokenAddress: string;
+ let zrxTokenAssetData: string;
+ let userAddresses: string[];
+ let coinbase: string;
+ let makerAddress: string;
+ let takerAddress: string;
+ let feeRecipient: string;
+ let anotherMakerAddress: string;
+ let makerTokenAddress: string;
+ let takerTokenAddress: string;
+ let makerAssetData: string;
+ let takerAssetData: string;
+ let signedOrder: SignedOrder;
+ let anotherSignedOrder: SignedOrder;
+ let contractAddresses: ContractAddresses;
+
+ before(async () => {
+ contractAddresses = await migrateOnceAsync();
+ await blockchainLifecycle.startAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
+ contractWrappers = new ContractWrappers(provider, config);
+ exchangeContractAddress = contractWrappers.exchange.address;
+ userAddresses = await web3Wrapper.getAvailableAddressesAsync();
+ zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress;
+ zrxTokenAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenAddress);
+ fillScenarios = new FillScenarios(
+ provider,
+ userAddresses,
+ zrxTokenAddress,
+ exchangeContractAddress,
+ contractWrappers.erc20Proxy.address,
+ contractWrappers.erc721Proxy.address,
+ );
+ [coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses;
+ [makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
+ takerTokenAddress = contractAddresses.etherToken;
+ [makerAssetData, takerAssetData] = [
+ assetDataUtils.encodeERC20AssetData(makerTokenAddress),
+ assetDataUtils.encodeERC20AssetData(takerTokenAddress),
+ ];
+
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerAssetData,
+ takerAssetData,
+ makerAddress,
+ constants.NULL_ADDRESS,
+ fillableAmount,
+ );
+ anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ zrxTokenAssetData,
+ takerAssetData,
+ makerAddress,
+ constants.NULL_ADDRESS,
+ fillableAmount,
+ );
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('#getOrdersAndTradersInfoAsync', () => {
+ let signedOrders: SignedOrder[];
+ let takerAddresses: string[];
+ let ordersInfo: OrderInfo[];
+ let tradersInfo: TraderInfo[];
+ beforeEach(async () => {
+ signedOrders = [signedOrder, anotherSignedOrder];
+ takerAddresses = [takerAddress, takerAddress];
+ const ordersAndTradersInfo = await contractWrappers.orderValidator.getOrdersAndTradersInfoAsync(
+ signedOrders,
+ takerAddresses,
+ );
+ ordersInfo = _.map(ordersAndTradersInfo, orderAndTraderInfo => orderAndTraderInfo.orderInfo);
+ tradersInfo = _.map(ordersAndTradersInfo, orderAndTraderInfo => orderAndTraderInfo.traderInfo);
+ });
+ it('should return the same number of order infos and trader infos as input orders', async () => {
+ expect(ordersInfo.length).to.be.equal(signedOrders.length);
+ expect(tradersInfo.length).to.be.equal(takerAddresses.length);
+ });
+ it('should return correct on-chain order info for input orders', async () => {
+ const firstOrderInfo = ordersInfo[0];
+ const secondOrderInfo = ordersInfo[1];
+ expect(firstOrderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(firstOrderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
+ expect(secondOrderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+ expect(secondOrderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('should return correct on-chain trader info for input takers', async () => {
+ const firstTraderInfo = tradersInfo[0];
+ const secondTraderInfo = tradersInfo[1];
+ expect(firstTraderInfo.makerBalance).to.bignumber.equal(new BigNumber(5));
+ expect(firstTraderInfo.makerAllowance).to.bignumber.equal(new BigNumber(5));
+ expect(firstTraderInfo.takerBalance).to.bignumber.equal(new BigNumber(0));
+ expect(firstTraderInfo.takerAllowance).to.bignumber.equal(new BigNumber(0));
+ expect(firstTraderInfo.makerZrxBalance).to.bignumber.equal(new BigNumber(5));
+ expect(firstTraderInfo.makerZrxAllowance).to.bignumber.equal(new BigNumber(5));
+ expect(firstTraderInfo.takerZrxBalance).to.bignumber.equal(new BigNumber(0));
+ expect(firstTraderInfo.takerZrxAllowance).to.bignumber.equal(new BigNumber(0));
+ expect(secondTraderInfo.makerBalance).to.bignumber.equal(new BigNumber(5));
+ expect(secondTraderInfo.makerAllowance).to.bignumber.equal(new BigNumber(5));
+ expect(secondTraderInfo.takerBalance).to.bignumber.equal(new BigNumber(0));
+ expect(secondTraderInfo.takerAllowance).to.bignumber.equal(new BigNumber(0));
+ expect(secondTraderInfo.makerZrxBalance).to.bignumber.equal(new BigNumber(5));
+ expect(secondTraderInfo.makerZrxAllowance).to.bignumber.equal(new BigNumber(5));
+ expect(secondTraderInfo.takerZrxBalance).to.bignumber.equal(new BigNumber(0));
+ expect(secondTraderInfo.takerZrxAllowance).to.bignumber.equal(new BigNumber(0));
+ });
+ });
+});
diff --git a/packages/contract-wrappers/test/revert_validation_test.ts b/packages/contract-wrappers/test/revert_validation_test.ts
new file mode 100644
index 000000000..efd5dd61f
--- /dev/null
+++ b/packages/contract-wrappers/test/revert_validation_test.ts
@@ -0,0 +1,115 @@
+import { BlockchainLifecycle, devConstants, web3Factory } from '@0x/dev-utils';
+import { FillScenarios } from '@0x/fill-scenarios';
+import { runMigrationsAsync } from '@0x/migrations';
+import { assetDataUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as chai from 'chai';
+import 'mocha';
+
+import { ContractWrappers } from '../src';
+
+import { chaiSetup } from './utils/chai_setup';
+import { constants } from './utils/constants';
+import { tokenUtils } from './utils/token_utils';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('Revert Validation ExchangeWrapper', () => {
+ let contractWrappers: ContractWrappers;
+ let userAddresses: string[];
+ let fillScenarios: FillScenarios;
+ let makerTokenAddress: string;
+ let takerTokenAddress: string;
+ let makerAddress: string;
+ let takerAddress: string;
+ let makerAssetData: string;
+ let takerAssetData: string;
+ let txHash: string;
+ let blockchainLifecycle: BlockchainLifecycle;
+ let web3Wrapper: Web3Wrapper;
+ const fillableAmount = new BigNumber(5);
+ const takerTokenFillAmount = new BigNumber(5);
+ let signedOrder: SignedOrder;
+ before(async () => {
+ // vmErrorsOnRPCResponse is useful for quick feedback and testing during development
+ // but is not the default behaviour in production. Here we ensure our failure cases
+ // are handled in an environment which behaves similar to production
+ const provider = web3Factory.getRpcProvider({
+ shouldUseInProcessGanache: true,
+ shouldThrowErrorsOnGanacheRPCResponse: false,
+ });
+ web3Wrapper = new Web3Wrapper(provider);
+ blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+ // Re-deploy the artifacts in this provider, rather than in the default provider exposed in
+ // the beforeAll hook. This is due to the fact that the default provider enabled vmErrorsOnRPCResponse
+ // and we are explicity testing with vmErrorsOnRPCResponse disabled.
+ const txDefaults = {
+ gas: devConstants.GAS_LIMIT,
+ from: devConstants.TESTRPC_FIRST_ADDRESS,
+ };
+ await blockchainLifecycle.startAsync();
+ const contractAddresses = await runMigrationsAsync(provider, txDefaults);
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
+ contractWrappers = new ContractWrappers(provider, config);
+ userAddresses = await web3Wrapper.getAvailableAddressesAsync();
+ fillScenarios = new FillScenarios(
+ provider,
+ userAddresses,
+ contractAddresses.zrxToken,
+ contractAddresses.exchange,
+ contractAddresses.erc20Proxy,
+ contractAddresses.erc721Proxy,
+ );
+ [, makerAddress, takerAddress] = userAddresses;
+ [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
+ [makerAssetData, takerAssetData] = [
+ assetDataUtils.encodeERC20AssetData(makerTokenAddress),
+ assetDataUtils.encodeERC20AssetData(takerTokenAddress),
+ ];
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ );
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('#fillOrderAsync', () => {
+ it('should throw the revert reason when shouldValidate is true and a fill would revert', async () => {
+ // Create a scenario where the fill will revert
+ const makerTokenBalance = await contractWrappers.erc20Token.getBalanceAsync(
+ makerTokenAddress,
+ makerAddress,
+ );
+ // Transfer all of the tokens from maker to create a failure scenario
+ txHash = await contractWrappers.erc20Token.transferAsync(
+ makerTokenAddress,
+ makerAddress,
+ takerAddress,
+ makerTokenBalance,
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ return expect(
+ contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress, {
+ shouldValidate: true,
+ }),
+ ).to.be.rejectedWith('TRANSFER_FAILED');
+ });
+ });
+});
diff --git a/packages/contract-wrappers/test/subscription_test.ts b/packages/contract-wrappers/test/subscription_test.ts
index 80d17576f..0fa6af40d 100644
--- a/packages/contract-wrappers/test/subscription_test.ts
+++ b/packages/contract-wrappers/test/subscription_test.ts
@@ -1,14 +1,20 @@
-import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
-import { DoneCallback } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { DoneCallback } from '@0x/types';
import * as _ from 'lodash';
import 'mocha';
import * as Sinon from 'sinon';
-import { ContractWrappers, DecodedLogEvent, ERC20TokenApprovalEventArgs, ERC20TokenEvents, Token } from '../src';
+import {
+ ContractWrappers,
+ ContractWrappersConfig,
+ DecodedLogEvent,
+ ERC20TokenApprovalEventArgs,
+ ERC20TokenEvents,
+} from '../src';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -17,17 +23,15 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('SubscriptionTest', () => {
let contractWrappers: ContractWrappers;
- let userAddresses: string[];
- let coinbase: string;
- let addressWithoutFunds: string;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
+ let config: ContractWrappersConfig;
+
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
+ config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ };
contractWrappers = new ContractWrappers(provider, config);
- userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- coinbase = userAddresses[0];
- addressWithoutFunds = userAddresses[1];
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
@@ -38,7 +42,6 @@ describe('SubscriptionTest', () => {
describe('#subscribe', () => {
const indexFilterValues = {};
let tokenAddress: string;
- const allowanceAmount = new BigNumber(42);
let stubs: Sinon.SinonStub[] = [];
before(() => {
const tokenAddresses = tokenUtils.getDummyERC20TokenAddresses();
@@ -52,7 +55,7 @@ describe('SubscriptionTest', () => {
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
(async () => {
const callback = (err: Error | null, _logEvent?: DecodedLogEvent<ERC20TokenApprovalEventArgs>) =>
- _.noop;
+ _.noop.bind(_);
contractWrappers.erc20Token.subscribe(
tokenAddress,
ERC20TokenEvents.Approval,
@@ -60,7 +63,7 @@ describe('SubscriptionTest', () => {
callback,
);
stubs = [
- Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockAsync').throws(
+ Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockIfExistsAsync').throws(
new Error('JSON RPC error'),
),
];
diff --git a/packages/contract-wrappers/test/transaction_encoder_test.ts b/packages/contract-wrappers/test/transaction_encoder_test.ts
index 10222dbc1..ef9eb2cf3 100644
--- a/packages/contract-wrappers/test/transaction_encoder_test.ts
+++ b/packages/contract-wrappers/test/transaction_encoder_test.ts
@@ -1,14 +1,15 @@
-import { BlockchainLifecycle } from '@0xproject/dev-utils';
-import { FillScenarios } from '@0xproject/fill-scenarios';
-import { assetDataUtils, ecSignOrderHashAsync, generatePseudoRandomSalt, orderHashUtils } from '@0xproject/order-utils';
-import { SignedOrder, SignerType } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { FillScenarios } from '@0x/fill-scenarios';
+import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils, signatureUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
import 'mocha';
import { ContractWrappers } from '../src';
import { TransactionEncoder } from '../src/utils/transaction_encoder';
import { constants } from './utils/constants';
+import { migrateOnceAsync } from './utils/migrate';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -31,23 +32,26 @@ describe('TransactionEncoder', () => {
const fillableAmount = new BigNumber(5);
const takerTokenFillAmount = new BigNumber(5);
let signedOrder: SignedOrder;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- blockPollingIntervalMs: 0,
- };
+
before(async () => {
+ const contractAddresses = await migrateOnceAsync();
await blockchainLifecycle.startAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
contractWrappers = new ContractWrappers(provider, config);
- exchangeContractAddress = contractWrappers.exchange.getContractAddress();
+ exchangeContractAddress = contractWrappers.exchange.address;
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- const zrxTokenAddress = tokenUtils.getProtocolTokenAddress();
+ const zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress;
fillScenarios = new FillScenarios(
provider,
userAddresses,
zrxTokenAddress,
exchangeContractAddress,
- contractWrappers.erc20Proxy.getContractAddress(),
- contractWrappers.erc721Proxy.getContractAddress(),
+ contractWrappers.erc20Proxy.address,
+ contractWrappers.erc721Proxy.address,
);
[coinbase, makerAddress, takerAddress, senderAddress] = userAddresses;
[makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
@@ -80,12 +84,7 @@ describe('TransactionEncoder', () => {
): Promise<void> => {
const salt = generatePseudoRandomSalt();
const encodedTransaction = encoder.getTransactionHex(data, salt, signerAddress);
- const signature = await ecSignOrderHashAsync(
- provider,
- encodedTransaction,
- signerAddress,
- SignerType.Default,
- );
+ const signature = await signatureUtils.ecSignHashAsync(provider, encodedTransaction, signerAddress);
txHash = await contractWrappers.exchange.executeTransactionAsync(
salt,
signerAddress,
diff --git a/packages/contract-wrappers/test/utils/constants.ts b/packages/contract-wrappers/test/utils/constants.ts
index 60c3370a2..ca6c574e4 100644
--- a/packages/contract-wrappers/test/utils/constants.ts
+++ b/packages/contract-wrappers/test/utils/constants.ts
@@ -1,4 +1,4 @@
-import { BigNumber } from '@0xproject/utils';
+import { BigNumber } from '@0x/utils';
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
@@ -15,4 +15,5 @@ export const constants = {
DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(10 ** 27), // tslint:disable-line:custom-no-magic-numbers
NUM_DUMMY_ERC20_TO_DEPLOY: 3,
NUM_DUMMY_ERC721_TO_DEPLOY: 1,
+ ZERO_AMOUNT: new BigNumber(0),
};
diff --git a/packages/contract-wrappers/test/utils/migrate.ts b/packages/contract-wrappers/test/utils/migrate.ts
new file mode 100644
index 000000000..665ce0faa
--- /dev/null
+++ b/packages/contract-wrappers/test/utils/migrate.ts
@@ -0,0 +1,18 @@
+import { ContractAddresses } from '@0x/contract-addresses';
+import { devConstants } from '@0x/dev-utils';
+import { runMigrationsOnceAsync } from '@0x/migrations';
+
+import { provider } from './web3_wrapper';
+
+/**
+ * Configures and runs the migrations exactly once. Any subsequent times this is
+ * called, it returns the cached addresses.
+ * @returns The addresses of contracts that were deployed during the migrations.
+ */
+export async function migrateOnceAsync(): Promise<ContractAddresses> {
+ const txDefaults = {
+ gas: devConstants.GAS_LIMIT,
+ from: devConstants.TESTRPC_FIRST_ADDRESS,
+ };
+ return runMigrationsOnceAsync(provider, txDefaults);
+}
diff --git a/packages/contract-wrappers/test/utils/token_utils.ts b/packages/contract-wrappers/test/utils/token_utils.ts
index 06a82ff6e..f8a88637f 100644
--- a/packages/contract-wrappers/test/utils/token_utils.ts
+++ b/packages/contract-wrappers/test/utils/token_utils.ts
@@ -1,14 +1,13 @@
-import { generatePseudoRandomSalt } from '@0xproject/order-utils';
-import { BigNumber } from '@0xproject/utils';
+import { DummyERC721TokenContract } from '@0x/abi-gen-wrappers';
+import { DummyERC721Token } from '@0x/contract-artifacts';
+import { generatePseudoRandomSalt } from '@0x/order-utils';
+import { BigNumber } from '@0x/utils';
-import { artifacts } from '../../src/artifacts';
-import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_erc721_token';
-
-import { constants } from './constants';
import { provider, txDefaults, web3Wrapper } from './web3_wrapper';
// Those addresses come from migrations. They're deterministic so it's relatively safe to hard-code them here.
// Before we were fetching them from the TokenRegistry but now we can't as it's deprecated and removed.
+// TODO(albrow): Import these from the migrations package instead of hard-coding them.
const DUMMY_ERC_20_ADRESSES = [
'0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f',
'0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db',
@@ -20,12 +19,6 @@ const DUMMY_ERC_20_ADRESSES = [
const DUMMY_ERC_721_ADRESSES = ['0x131855dda0aaff096f6854854c55a4debf61077a'];
export const tokenUtils = {
- getProtocolTokenAddress(): string {
- return artifacts.ZRXToken.networks[constants.TESTRPC_NETWORK_ID].address;
- },
- getWethTokenAddress(): string {
- return artifacts.EtherToken.networks[constants.TESTRPC_NETWORK_ID].address;
- },
getDummyERC20TokenAddresses(): string[] {
return DUMMY_ERC_20_ADRESSES;
},
@@ -33,12 +26,7 @@ export const tokenUtils = {
return DUMMY_ERC_721_ADRESSES;
},
async mintDummyERC721Async(address: string, tokenOwner: string): Promise<BigNumber> {
- const erc721 = new DummyERC721TokenContract(
- artifacts.DummyERC721Token.compilerOutput.abi,
- address,
- provider,
- txDefaults,
- );
+ const erc721 = new DummyERC721TokenContract(DummyERC721Token.compilerOutput.abi, address, provider, txDefaults);
const tokenId = generatePseudoRandomSalt();
const txHash = await erc721.mint.sendTransactionAsync(tokenOwner, tokenId);
web3Wrapper.awaitTransactionSuccessAsync(txHash);
diff --git a/packages/contract-wrappers/test/utils/web3_wrapper.ts b/packages/contract-wrappers/test/utils/web3_wrapper.ts
index 02c8c5918..4e86ebeba 100644
--- a/packages/contract-wrappers/test/utils/web3_wrapper.ts
+++ b/packages/contract-wrappers/test/utils/web3_wrapper.ts
@@ -1,5 +1,5 @@
-import { devConstants, web3Factory } from '@0xproject/dev-utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { devConstants, web3Factory } from '@0x/dev-utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
const txDefaults = {
diff --git a/packages/contract-wrappers/tsconfig.json b/packages/contract-wrappers/tsconfig.json
index e35816553..2ee711adc 100644
--- a/packages/contract-wrappers/tsconfig.json
+++ b/packages/contract-wrappers/tsconfig.json
@@ -1,7 +1,8 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
- "outDir": "lib"
+ "outDir": "lib",
+ "rootDir": "."
},
"include": ["./src/**/*", "./test/**/*"]
}
diff --git a/packages/contract-wrappers/tslint.json b/packages/contract-wrappers/tslint.json
index ffaefe83a..dd9053357 100644
--- a/packages/contract-wrappers/tslint.json
+++ b/packages/contract-wrappers/tslint.json
@@ -1,3 +1,3 @@
{
- "extends": ["@0xproject/tslint-config"]
+ "extends": ["@0x/tslint-config"]
}
diff --git a/packages/contract-wrappers/typedoc-tsconfig.json b/packages/contract-wrappers/typedoc-tsconfig.json
new file mode 100644
index 000000000..c9b0af1ae
--- /dev/null
+++ b/packages/contract-wrappers/typedoc-tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../typedoc-tsconfig",
+ "compilerOptions": {
+ "outDir": "lib"
+ },
+ "include": ["./src/**/*", "./test/**/*"]
+}