diff options
Diffstat (limited to 'packages/0x.js')
85 files changed, 5431 insertions, 6019 deletions
diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index 963b3d56c..7fc1d9bba 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -1,11 +1,43 @@ # CHANGELOG -v0.27.1 - _November 28, 2017_ ------------------------- +## v0.30.1 - _January 18, 2018_ + + * Fix a bug allowing negative fill values (#212) + * Fix a bug that made it impossible to pass a custom ZRX address (#341) + +## v0.30.0 - _January 17, 2018_ + + * Add an error parameter to the order watcher callback (#312) + * Fix a bug making it impossible to catch some errors from awaitTransactionMinedAsync (#312) + * Fix a bug in fillOrdersUpTo validation making it impossible to fill up to if user doesn't have enough balance to fully fill all the orders (#321) + +## v0.29.1 - _January 11, 2018_ + + * Fixed bignumber config issue #301 (#305) + +## v0.29.0 - _December 28, 2017_ + + * Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287) + * `toBaseUnitAmount` throws if amount supplied has too many decimals (#287) + +## v0.28.0 - _December 20, 2017_ + + * Add `etherTokenAddress` arg to `depositAsync` and `withdrawAsync` methods on `zeroEx.etherToken` (#267) + * Removed accidentally included `unsubscribeAll` method from `zeroEx.proxy`, `zeroEx.etherToken` and `zeroEx.tokenRegistry` (#267) + * Removed `etherTokenContractAddress` from `ZeroEx` constructor arg `ZeroExConfig` (#267) + * Rename `SubscriptionOpts` to `BlockRange` (#272) + * Add `zeroEx.etherToken.subscribe`, `zeroEx.etherToken.unsubscribe`, `zeroEx.etherToken.unsubscribeAll` (#277) + * Add `zeroEx.etherToken.getLogsAsync` (#277) + * Add new public types `BlockParamLiteral`, `EtherTokenEvents`, `EtherTokenContractEventArgs`, `DepositContractEventArgs`, `WithdrawalContractEventArgs` (#277) + * Support `Deposit` and `Withdraw` events on etherToken (#277) + * Improve the error message when taker is not a string (#278) + +## v0.27.1 - _November 28, 2017_ + * Export `TransactionOpts` type -v0.27.0 - _November 28, 2017_ ------------------------- +## v0.27.0 - _November 28, 2017_ + * Make `ZeroExConfig` required parameter of `ZeroEx` constructor (#233) * Add a required property `networkId` to `ZeroExConfig` (#233) * Make all `getContractAddress` functions, `zeroEx.exchange.subscribe`, `zeroEx.exchange.getZRXTokenAddress` sync (#233) @@ -16,66 +48,66 @@ v0.27.0 - _November 28, 2017_ * All transaction sending methods now call `estimateGas` if no gas amount was supplied (#235) * Modify order validation methods to validate against the `latest` block, not against the `pending` block (#236) -v0.26.0 - _November 21, 2017_ ------------------------- +## v0.26.0 - _November 21, 2017_ + * Add post-formatter for logs converting `blockNumber`, `logIndex`, `transactionIndex` from hexes to numbers (#231) * Remove support for Async callback types when used in Subscribe functions (#222) * In OrderWatcher subscribe to ZRX Token Transfer and Approval events when maker token is different (#225) -v0.25.1 - _November 13, 2017_ ------------------------- +## v0.25.1 - _November 13, 2017_ + * Standardise on Cancelled over Canceled (#217) * Add missing `DecodedLogEvent` type to exported types (#205) * Normalized the transactionReceipt status to be `null|0|1`, 1 meaning transaction execution successful, 0 unsuccessful and `null` if it is a pre-byzantinium transaction. (#200) -v0.23.0 - _November 12, 2017_ ------------------------- +## v0.23.0 - _November 12, 2017_ + * Fixed unhandled promise rejection error in subscribe methods (#209) * Subscribe callbacks now receive an error object as their first argument -v0.22.6 - _November 10, 2017_ ------------------------- +## v0.22.6 - _November 10, 2017_ + * Add a timeout parameter to transaction awaiting (#206) -v0.22.5 - _November 7, 2017_ ------------------------- +## v0.22.5 - _November 7, 2017_ + * Re-publish v0.22.4 to fix publishing issue -v0.22.4 - _October 25, 2017_ ------------------------- +## v0.22.4 - _October 25, 2017_ + * Upgraded bignumber.js to a new version that ships with native typings -v0.22.3 - _October 25, 2017_ ------------------------- +## v0.22.3 - _October 25, 2017_ + * Fixed an issue with new version of testrpc and unlimited proxy allowance (#199) -v0.22.2 - _October 24, 2017_ ------------------------- +## v0.22.2 - _October 24, 2017_ + * Fixed rounding of maker fill amount and incorrect validation of partial fees (#197) -v0.22.0 - _October 16, 2017_ ------------------------- +## v0.22.0 - _October 16, 2017_ + * Started using `OrderFillRequest` interface instead of `OrderFillOrKillRequest` interface for `zeroEx.exchange.batchFillOrKill` (#187) * Removed `OrderFillOrKillRequest` (#187) -v0.21.4 - _October 13, 2017_ ------------------------- +## v0.21.4 - _October 13, 2017_ + * Made 0x.js more type-safe by making `getLogsAsync` and `subscribe/subscribeAsync` generics parametrized with arg type (#194) -v0.21.3 - _October 12, 2017_ ------------------------- +## v0.21.3 - _October 12, 2017_ + * Fixed a bug causing order fills to throw `INSUFFICIENT_TAKER_ALLOWANCE` (#193) -v0.21.2 - _October 11, 2017_ ------------------------- +## v0.21.2 - _October 11, 2017_ + * Exported `ContractEventArg` as a public type (#190) -v0.21.1 - _October 11, 2017_ ------------------------- +## v0.21.1 - _October 11, 2017_ + * Fixed a bug in subscriptions (#189) -v0.21.0 - _October 10, 2017_ ------------------------- +## v0.21.0 - _October 10, 2017_ + * Complete rewrite of subscription logic (#182) * Subscriptions no longer return historical logs. If you want them - use `getLogsAsync` * Subscriptions now use [ethereumjs-blockstream](https://github.com/ethereumjs/ethereumjs-blockstream) under the hood @@ -89,77 +121,77 @@ v0.21.0 - _October 10, 2017_ * Renamed `zeroEx.token.stopWatchingAllEventsAsync` to `zeroEx.token.unsubscribeAll` * Fixed the batch fills validation by emulating all balance & proxy allowance changes (#185) -v0.20.0 - _October 5, 2017_ ------------------------- +## v0.20.0 - _October 5, 2017_ + * Add `zeroEx.token.getLogsAsync` (#178) * Add `zeroEx.exchange.getLogsAsync` (#178) * Fixed fees validation when one of the tokens transferred is ZRX (#181) -v0.19.0 - _September 29, 2017_ ------------------------- +## v0.19.0 - _September 29, 2017_ + * Made order validation optional (#172) * Added Ropsten testnet support (#173) * Fixed a bug causing awaitTransactionMinedAsync to DDos backend nodes (#175) -v0.18.0 - _September 26, 2017_ ------------------------- +## v0.18.0 - _September 26, 2017_ + * Added `zeroEx.exchange.validateOrderFillableOrThrowAsync` to simplify orderbook pruning (#170) -v0.17.0 - _September 26, 2017_ ------------------------- +## v0.17.0 - _September 26, 2017_ + * Made `zeroEx.exchange.getZRXTokenAddressAsync` public (#171) -v0.16.0 - _September 20, 2017_ ------------------------- +## v0.16.0 - _September 20, 2017_ + * Added the ability to specify custom contract addresses to be used with 0x.js (#165) * ZeroExConfig.exchangeContractAddress * ZeroExConfig.tokenRegistryContractAddress * ZeroExConfig.etherTokenContractAddress * Added `zeroEx.tokenRegistry.getContractAddressAsync` (#165) -v0.15.0 - _September 8, 2017_ ------------------------- +## v0.15.0 - _September 8, 2017_ + * Added the ability to specify a historical `blockNumber` at which to query the blockchain's state when calling a token or exchange method (#161) -v0.14.2 - _September 7, 2017_ ------------------------- +## v0.14.2 - _September 7, 2017_ + * Fixed an issue with bignumber.js types not found (#160) -v0.14.1 - _September 7, 2017_ ------------------------- +## v0.14.1 - _September 7, 2017_ + * Fixed an issue with Artifact type not found (#159) -v0.14.0 - _September 6, 2017_ ------------------------- +## v0.14.0 - _September 6, 2017_ + * Added `zeroEx.exchange.throwLogErrorsAsErrors` method to public interface (#157) * Fixed an issue with overlapping async intervals in `zeroEx.awaitTransactionMinedAsync` (#157) * Fixed an issue with log decoder returning `BigNumber`s as `strings` (#157) -v0.13.0 - _September 6, 2017_ ------------------------- +## v0.13.0 - _September 6, 2017_ + * Made all the functions submitting transactions to the network to immediately return transaction hash (#151) * Added `zeroEx.awaitTransactionMinedAsync` (#151) * Added `TransactionReceiptWithDecodedLogs`, `LogWithDecodedArgs`, `DecodedLogArgs` to public types (#151) * Added signature validation to `validateFillOrderThrowIfInvalidAsync` (#152) -v0.12.1 - _September 2, 2017_ ------------------------- +## v0.12.1 - _September 2, 2017_ + * Added the support for web3@1.x.x provider (#142) * Added the optional `zeroExConfig` parameter to the constructor of `ZeroEx` (#139) * Added the ability to specify `gasPrice` when instantiating `ZeroEx` (#139) -v0.11.0 - _August 24, 2017_ ------------------------- +## v0.11.0 - _August 24, 2017_ + * Added `zeroEx.token.setUnlimitedProxyAllowanceAsync` (#137) * Added `zeroEx.token.setUnlimitedAllowanceAsync` (#137) * Added `zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS` (#137) -v0.10.4 - _Aug 24, 2017_ ------------------------- +## v0.10.4 - _Aug 24, 2017_ + * Fixed a bug where checksummed addresses were being pulled from artifacts and not lower-cased. (#135) -v0.10.1 - _Aug 24, 2017_ ------------------------- +## v0.10.1 - _Aug 24, 2017_ + * Added `zeroEx.exchange.validateFillOrderThrowIfInvalidAsync` (#128) * Added `zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync` (#128) * Added `zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync` (#128) @@ -173,21 +205,21 @@ v0.10.1 - _Aug 24, 2017_ * Added clear error message when checksummed address is passed to a public method (#124) * Fixes the description of `shouldThrowOnInsufficientBalanceOrAllowance` in docs (#127) -v0.9.3 - _Aug 22, 2017_ ------------------------- +## v0.9.3 - _Aug 22, 2017_ + * Update contract artifacts to include latest Kovan and Mainnet deploys (#118) -v0.9.2 - _Aug 21, 2017_ ------------------------- +## v0.9.2 - _Aug 21, 2017_ + * *This version was unpublished because of a publishing issue.* * Update contract artifacts to include latest Kovan and Mainnet deploys (#118) -v0.9.1 - _Aug. 16, 2017_ ------------------------- +## v0.9.1 - _Aug. 16, 2017_ + * Fixed the bug causing `zeroEx.token.getBalanceAsync()` to fail if no addresses available (#120) -v0.9.0 - _Jul. 26, 2017_ ------------------------- +## v0.9.0 - _Jul. 26, 2017_ + * Migrated to the new version of smart contracts (#101) * Removed the ability to call methods on multiple authorized Exchange smart contracts (#106) * Made `zeroEx.getOrderHashHex` a static method (#107) @@ -197,8 +229,8 @@ v0.9.0 - _Jul. 26, 2017_ * Updated to typescript v2.4 (#104) * Fixed an issue with incorrect balance/allowance validation when ZRX is one of the tokens traded (#109) -v0.8.0 - _Jul. 4, 2017_ ------------------------- +## v0.8.0 - _Jul. 4, 2017_ + * Added the ability to call methods on different authorized versions of the Exchange smart contract (#82) * Updated contract artifacts to reflect latest changes to the smart contracts (0xproject/contracts#59) * Added `zeroEx.proxy.isAuthorizedAsync` and `zeroEx.proxy.getAuthorizedAddressesAsync` (#89) @@ -210,35 +242,35 @@ v0.8.0 - _Jul. 4, 2017_ * `zeroEx.tokenRegistry.invalidateContractInstance` * Fixed the bug where `zeroEx.setProviderAsync` didn't invalidate etherToken contract's instance -v0.7.1 - _Jun. 26, 2017_ ------------------------- +## v0.7.1 - _Jun. 26, 2017_ + * Added the ability to convert Ether to wrapped Ether tokens and back via `zeroEx.etherToken.depostAsync` and `zeroEx.etherToken.withdrawAsync` (#81) -v0.7.0 - _Jun. 22, 2017_ ------------------------- +## v0.7.0 - _Jun. 22, 2017_ + * Added Kovan smart contract artifacts (#78) * Started returning fillAmount from `fillOrderAsync` and `fillUpToAsync` (#72) * Started returning cancelledAmount from `cancelOrderAsync` (#72) * Renamed type `LogCancelArgs` to `LogCancelContractEventArgs` and `LogFillArgs` to `LogFillContractEventArgs` -v0.6.2 - _Jun. 21, 2017_ ------------------------- +## v0.6.2 - _Jun. 21, 2017_ + * Reduced bundle size * Improved documentation -v0.6.1 - _Jun. 19, 2017_ ------------------------- +## v0.6.1 - _Jun. 19, 2017_ + * Improved documentation -v0.6.0 - _Jun. 19, 2017_ ------------------------- +## v0.6.0 - _Jun. 19, 2017_ + * Made `ZeroEx` class accept `Web3Provider` instance instead of `Web3` instance * Added types for contract event arguments -v0.5.2 - _Jun. 15, 2017_ ------------------------- +## v0.5.2 - _Jun. 15, 2017_ + * Fixed the bug in `postpublish` script that caused that only unminified UMD bundle was uploaded to release page -v0.5.1 - _Jun. 15, 2017_ ------------------------- +## v0.5.1 - _Jun. 15, 2017_ + * Added `postpublish` script to publish to Github Releases with assets. diff --git a/packages/0x.js/README.md b/packages/0x.js/README.md index 6cdcbde70..bac4fa5d8 100644 --- a/packages/0x.js/README.md +++ b/packages/0x.js/README.md @@ -1,11 +1,10 @@ -0x.js ------ +## 0x.js ## Installation 0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package. -#### CommonJS *(recommended)*: +#### CommonJS _(recommended)_: **Install** @@ -16,7 +15,7 @@ npm install 0x.js --save **Import** ```javascript -import {ZeroEx} from '0x.js'; +import { ZeroEx } from '0x.js'; ``` #### UMD: diff --git a/packages/0x.js/contract_templates/contract.mustache b/packages/0x.js/contract_templates/contract.mustache new file mode 100644 index 000000000..3e501cce6 --- /dev/null +++ b/packages/0x.js/contract_templates/contract.mustache @@ -0,0 +1,25 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +// tslint:disable-next-line:no-unused-variable +import { TxData, TxDataPayable } from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import * as Web3 from 'web3'; + +import {BaseContract} from './base_contract'; + +export class {{contractName}}Contract extends BaseContract { +{{#each methods}} + {{#this.constant}} + {{> call contractName=../contractName}} + {{/this.constant}} + {{^this.constant}} + {{> tx contractName=../contractName}} + {{/this.constant}} +{{/each}} + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/contract_templates/partials/call.mustache b/packages/0x.js/contract_templates/partials/call.mustache new file mode 100644 index 000000000..ef4bda724 --- /dev/null +++ b/packages/0x.js/contract_templates/partials/call.mustache @@ -0,0 +1,15 @@ +public {{this.name}} = { + async callAsync( + {{> typed_params inputs=inputs}} + defaultBlock?: Web3.BlockParam, + ): Promise<{{> return_type outputs=outputs}}> { + const self = this as {{contractName}}Contract; + const result = await promisify<{{> return_type outputs=outputs}}>( + self.web3ContractInstance.{{this.name}}.call, + self.web3ContractInstance, + )( + {{> params inputs=inputs}} + ); + return result; + }, +}; diff --git a/packages/0x.js/contract_templates/partials/params.mustache b/packages/0x.js/contract_templates/partials/params.mustache new file mode 100644 index 000000000..ac5d4ae85 --- /dev/null +++ b/packages/0x.js/contract_templates/partials/params.mustache @@ -0,0 +1,3 @@ +{{#each inputs}} +{{name}}, +{{/each}} diff --git a/packages/0x.js/contract_templates/partials/return_type.mustache b/packages/0x.js/contract_templates/partials/return_type.mustache new file mode 100644 index 000000000..383961a40 --- /dev/null +++ b/packages/0x.js/contract_templates/partials/return_type.mustache @@ -0,0 +1,6 @@ +{{#singleReturnValue}} +{{#returnType outputs.0.type}}{{/returnType}} +{{/singleReturnValue}} +{{^singleReturnValue}} +[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}] +{{/singleReturnValue}} diff --git a/packages/0x.js/contract_templates/partials/tx.mustache b/packages/0x.js/contract_templates/partials/tx.mustache new file mode 100644 index 000000000..8a43e5319 --- /dev/null +++ b/packages/0x.js/contract_templates/partials/tx.mustache @@ -0,0 +1,51 @@ +public {{this.name}} = { + async sendTransactionAsync( + {{> typed_params inputs=inputs}} + {{#this.payable}} + txData: TxDataPayable = {}, + {{/this.payable}} + {{^this.payable}} + txData: TxData = {}, + {{/this.payable}} + ): Promise<string> { + const self = this as {{contractName}}Contract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.{{this.name}}.estimateGasAsync.bind( + self, + {{> params inputs=inputs}} + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.{{this.name}}, self.web3ContractInstance, + )( + {{> params inputs=inputs}} + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + {{> typed_params inputs=inputs}} + txData: TxData = {}, + ): Promise<number> { + const self = this as {{contractName}}Contract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.{{this.name}}.estimateGas, self.web3ContractInstance, + )( + {{> params inputs=inputs}} + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + {{> typed_params inputs=inputs}} + txData: TxData = {}, + ): string { + const self = this as {{contractName}}Contract; + const abiEncodedTransactionData = self.web3ContractInstance.{{this.name}}.getData(); + return abiEncodedTransactionData; + }, +}; diff --git a/packages/0x.js/contract_templates/partials/typed_params.mustache b/packages/0x.js/contract_templates/partials/typed_params.mustache new file mode 100644 index 000000000..3ea4b2e95 --- /dev/null +++ b/packages/0x.js/contract_templates/partials/typed_params.mustache @@ -0,0 +1,3 @@ +{{#each inputs}} + {{name}}: {{#parameterType type}}{{/parameterType}}, +{{/each}} diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 7b267fa8e..fb27f48de 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,106 +1,97 @@ { - "name": "0x.js", - "version": "0.27.1", - "description": "A javascript library for interacting with the 0x protocol", - "keywords": [ - "0x.js", - "0xproject", - "ethereum", - "tokens", - "exchange" - ], - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "prebuild": "npm run clean", - "build": "run-p build:umd:prod build:commonjs; exit 0;", - "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR", - "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json", - "generate_contract_wrappers": "abi-gen --abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json' --templates ../abi-gen-templates/ --output src/contract_wrappers/generated --fileExtension ts", - "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "test:circleci": "run-s test:coverage report_test_coverage && if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi", - "test": "run-s clean test:commonjs", - "test:umd": "./scripts/test_umd.sh", - "test:coverage": "nyc npm run test --all", - "report_test_coverage": "nyc report --reporter=text-lcov | coveralls", - "update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;", - "clean": "shx rm -rf _bundles lib test_temp", - "build:umd:dev": "webpack", - "build:umd:prod": "NODE_ENV=production webpack", - "build:commonjs": "tsc && copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts;", - "test:commonjs": "run-s build:commonjs run_mocha", - "pretest:umd": "run-s clean build:umd:dev build:commonjs", - "substitute_umd_bundle": "shx mv _bundles/* lib/src", - "run_mocha": "mocha lib/test/**/*_test.js --timeout 5000 --bail --exit" - }, - "config": { - "artifacts": "TokenTransferProxy Exchange TokenRegistry Token EtherToken" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js" - }, - "license": "Apache-2.0", - "engines": { - "node": ">=6.0.0" - }, - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@0xproject/types": "^0.0.1", - "@types/bintrees": "^1.0.2", - "@types/jsonschema": "^1.1.1", - "@types/lodash": "^4.14.86", - "@types/mocha": "^2.2.42", - "@types/node": "^8.0.53", - "@types/sinon": "^2.2.2", - "@types/uuid": "^3.4.2", - "abi-gen": "^0.0.1", - "abi-gen-templates": "^0.0.1", - "awesome-typescript-loader": "^3.1.3", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-as-promised-typescript-typings": "^0.0.3", - "chai-bignumber": "^2.0.1", - "chai-typescript-typings": "^0.0.1", - "copyfiles": "^1.2.0", - "coveralls": "^3.0.0", - "dirty-chai": "^2.0.1", - "json-loader": "^0.5.4", - "mocha": "^4.0.1", - "npm-run-all": "^4.1.2", - "nyc": "^11.0.1", - "opn-cli": "^3.1.0", - "request": "^2.81.0", - "request-promise-native": "^1.0.4", - "shx": "^0.2.2", - "sinon": "^4.0.0", - "source-map-support": "^0.5.0", - "truffle-hdwallet-provider": "^0.0.3", - "tslint": "5.8.0", - "typedoc": "~0.8.0", - "types-bn": "^0.0.1", - "types-ethereumjs-util": "0xProject/types-ethereumjs-util", - "typescript": "~2.6.1", - "web3-provider-engine": "^13.0.1", - "web3-typescript-typings": "^0.7.2", - "webpack": "^3.1.0" - }, - "dependencies": { - "@0xproject/assert": "^0.0.6", - "@0xproject/json-schemas": "^0.6.9", - "@0xproject/utils": "^0.0.1", - "@0xproject/web3-wrapper": "^0.0.1", - "bignumber.js": "~4.1.0", - "bintrees": "^1.0.2", - "bn.js": "^4.11.8", - "compare-versions": "^3.0.1", - "ethereumjs-abi": "^0.6.4", - "ethereumjs-blockstream": "^2.0.6", - "ethereumjs-util": "^5.1.1", - "find-versions": "^2.0.0", - "js-sha3": "^0.6.1", - "lodash": "^4.17.4", - "uuid": "^3.1.0", - "web3": "^0.20.0" - } + "name": "0x.js", + "version": "0.30.1", + "description": "A javascript library for interacting with the 0x protocol", + "keywords": [ + "0x.js", + "0xproject", + "ethereum", + "tokens", + "exchange" + ], + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "scripts": { + "prebuild": "run-s clean generate_contract_wrappers", + "build": "run-p build:umd:prod build:commonjs; exit 0;", + "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR", + "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json", + "generate_contract_wrappers": "node ../abi-gen/lib/index.js --abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --templates contract_templates --output src/contract_wrappers/generated", + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "test:circleci": "run-s test:coverage report_test_coverage", + "test": "run-s clean test:commonjs", + "test:coverage": "nyc npm run test --all", + "report_test_coverage": "nyc report --reporter=text-lcov | coveralls", + "update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;", + "clean": "shx rm -rf _bundles lib test_temp", + "build:umd:prod": "NODE_ENV=production webpack", + "build:commonjs": "tsc && copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts;", + "test:commonjs": "run-s build:commonjs run_mocha", + "run_mocha": "mocha lib/test/**/*_test.js --timeout 10000 --bail --exit" + }, + "config": { + "artifacts": "TokenTransferProxy Exchange TokenRegistry Token EtherToken" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js" + }, + "license": "Apache-2.0", + "engines": { + "node": ">=6.0.0" + }, + "devDependencies": { + "@0xproject/abi-gen": "^0.1.3", + "@0xproject/dev-utils": "^0.0.6", + "@0xproject/tslint-config": "^0.4.3", + "@0xproject/types": "^0.1.5", + "@types/bintrees": "^1.0.2", + "@types/jsonschema": "^1.1.1", + "@types/lodash": "^4.14.86", + "@types/mocha": "^2.2.42", + "@types/node": "^8.0.53", + "@types/sinon": "^2.2.2", + "@types/uuid": "^3.4.2", + "awesome-typescript-loader": "^3.1.3", + "chai": "^4.0.1", + "chai-as-promised": "^7.1.0", + "chai-as-promised-typescript-typings": "^0.0.5", + "chai-bignumber": "^2.0.1", + "chai-typescript-typings": "^0.0.2", + "copyfiles": "^1.2.0", + "coveralls": "^3.0.0", + "dirty-chai": "^2.0.1", + "json-loader": "^0.5.4", + "mocha": "^4.0.1", + "npm-run-all": "^4.1.2", + "nyc": "^11.0.1", + "opn-cli": "^3.1.0", + "request": "^2.81.0", + "request-promise-native": "^1.0.4", + "shx": "^0.2.2", + "sinon": "^4.0.0", + "source-map-support": "^0.5.0", + "truffle-hdwallet-provider": "^0.0.3", + "tslint": "5.8.0", + "typedoc": "~0.8.0", + "typescript": "~2.6.1", + "web3-provider-engine": "^13.0.1", + "web3-typescript-typings": "^0.9.5", + "webpack": "^3.1.0" + }, + "dependencies": { + "@0xproject/assert": "^0.0.12", + "@0xproject/json-schemas": "^0.7.4", + "@0xproject/utils": "^0.2.1", + "@0xproject/web3-wrapper": "^0.1.6", + "bintrees": "^1.0.2", + "bn.js": "^4.11.8", + "ethereumjs-abi": "^0.6.4", + "ethereumjs-blockstream": "^2.0.6", + "ethereumjs-util": "^5.1.1", + "js-sha3": "^0.6.1", + "lodash": "^4.17.4", + "uuid": "^3.1.0", + "web3": "^0.20.0" + } } diff --git a/packages/0x.js/scripts/postpublish.js b/packages/0x.js/scripts/postpublish.js index 28484a8bd..1be964478 100644 --- a/packages/0x.js/scripts/postpublish.js +++ b/packages/0x.js/scripts/postpublish.js @@ -8,26 +8,21 @@ const S3BucketPath = 's3://0xjs-docs-jsons/'; let tag; let version; -postpublish_utils.getLatestTagAndVersionAsync(subPackageName) +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) .then(function(result) { tag = result.tag; version = result.version; - const releaseName = postpublish_utils.getReleaseName(subPackageName, version); - const assets = [ - __dirname + '/../_bundles/index.js', - __dirname + '/../_bundles/index.min.js', - ]; - return postpublish_utils.publishReleaseNotes(tag, releaseName, assets); + const releaseName = postpublish_utils.getReleaseName(subPackageName, version); + const assets = [__dirname + '/../_bundles/index.js', __dirname + '/../_bundles/index.min.js']; + return postpublish_utils.publishReleaseNotes(tag, releaseName, assets); }) .then(function(release) { console.log('POSTPUBLISH: Release successful, generating docs...'); const jsonFilePath = __dirname + '/../' + postpublish_utils.generatedDocsDirectoryName + '/index.json'; - return execAsync( - 'JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json', - { - cwd, - } - ); + return execAsync('JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json', { + cwd, + }); }) .then(function(result) { if (result.stderr !== '') { @@ -39,6 +34,7 @@ postpublish_utils.getLatestTagAndVersionAsync(subPackageName) return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', { cwd, }); - }).catch (function(err) { + }) + .catch(function(err) { throw err; }); diff --git a/packages/0x.js/scripts/test_umd.sh b/packages/0x.js/scripts/test_umd.sh deleted file mode 100755 index e3eba088a..000000000 --- a/packages/0x.js/scripts/test_umd.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -# This script runs umd tests and cleans up after them while preserving the `return_code` for CI -# UMD tests should only be run after building the commonjs because they reuse some of the commonjs build artifacts -run-s substitute_umd_bundle run_mocha -return_code=$? -exit $return_code diff --git a/packages/0x.js/src/0x.ts b/packages/0x.js/src/0x.ts index 935e4ac1a..503a937c4 100644 --- a/packages/0x.js/src/0x.ts +++ b/packages/0x.js/src/0x.ts @@ -1,38 +1,32 @@ -import {schemas, SchemaValidator} from '@0xproject/json-schemas'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { schemas, SchemaValidator } from '@0xproject/json-schemas'; +import { BigNumber, intervalUtils } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import {artifacts} from './artifacts'; -import {bigNumberConfigs} from './bignumber_config'; -import {EtherTokenWrapper} from './contract_wrappers/ether_token_wrapper'; -import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper'; -import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper'; -import {TokenTransferProxyWrapper} from './contract_wrappers/token_transfer_proxy_wrapper'; -import {TokenWrapper} from './contract_wrappers/token_wrapper'; -import {OrderStateWatcher} from './order_watcher/order_state_watcher'; -import {zeroExConfigSchema} from './schemas/zero_ex_config_schema'; +import { artifacts } from './artifacts'; +import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper'; +import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper'; +import { TokenRegistryWrapper } from './contract_wrappers/token_registry_wrapper'; +import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_proxy_wrapper'; +import { TokenWrapper } from './contract_wrappers/token_wrapper'; +import { OrderStateWatcher } from './order_watcher/order_state_watcher'; +import { zeroExConfigSchema } from './schemas/zero_ex_config_schema'; import { ECSignature, Order, - OrderStateWatcherConfig, SignedOrder, TransactionReceiptWithDecodedLogs, Web3Provider, ZeroExConfig, ZeroExError, } from './types'; -import {AbiDecoder} from './utils/abi_decoder'; -import {assert} from './utils/assert'; -import {constants} from './utils/constants'; -import {intervalUtils} from './utils/interval_utils'; -import {OrderStateUtils} from './utils/order_state_utils'; -import {signatureUtils} from './utils/signature_utils'; -import {utils} from './utils/utils'; - -// Customize our BigNumber instances -bigNumberConfigs.configure(); +import { AbiDecoder } from './utils/abi_decoder'; +import { assert } from './utils/assert'; +import { constants } from './utils/constants'; +import { decorators } from './utils/decorators'; +import { signatureUtils } from './utils/signature_utils'; +import { utils } from './utils/utils'; /** * The ZeroEx class is the single entry-point into the 0x.js library. It contains all of the library's functionality @@ -130,7 +124,7 @@ export class ZeroEx { * @return The amount in units. */ public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber { - assert.isBigNumber('amount', amount); + assert.isValidBaseUnitAmount('amount', amount); assert.isNumber('decimals', decimals); const aUnit = new BigNumber(10).pow(decimals); @@ -151,6 +145,10 @@ export class ZeroEx { const unit = new BigNumber(10).pow(decimals); const baseUnitAmount = amount.times(unit); + const hasDecimals = baseUnitAmount.decimalPlaces() !== 0; + if (hasDecimals) { + throw new Error(`Invalid unit amount: ${amount.toString()} - Too many decimal places`); + } return baseUnitAmount; } /** @@ -158,7 +156,8 @@ export class ZeroEx { * @param order An object that conforms to the Order or SignedOrder interface definitions. * @return The resulting orderHash from hashing the supplied order. */ - public static getOrderHashHex(order: Order|SignedOrder): string { + @decorators.syncZeroExErrorHandler + public static getOrderHashHex(order: Order | SignedOrder): string { assert.doesConformToSchema('order', order, schemas.orderSchema); const orderHashHex = utils.getOrderHashHex(order); return orderHashHex; @@ -185,27 +184,27 @@ export class ZeroEx { config.networkId, config.tokenTransferProxyContractAddress, ); - this.token = new TokenWrapper( - this._web3Wrapper, - config.networkId, - this._abiDecoder, - this.proxy, - ); + this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.proxy); this.exchange = new ExchangeWrapper( this._web3Wrapper, config.networkId, this._abiDecoder, this.token, config.exchangeContractAddress, + config.zrxContractAddress, ); this.tokenRegistry = new TokenRegistryWrapper( - this._web3Wrapper, config.networkId, config.tokenRegistryContractAddress, - ); - this.etherToken = new EtherTokenWrapper( - this._web3Wrapper, config.networkId, this.token, config.etherTokenContractAddress, + this._web3Wrapper, + config.networkId, + config.tokenRegistryContractAddress, ); + this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.token); this.orderStateWatcher = new OrderStateWatcher( - this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig, + this._web3Wrapper, + this._abiDecoder, + this.token, + this.exchange, + config.orderWatcherConfig, ); } /** @@ -215,12 +214,17 @@ export class ZeroEx { * @param networkId The id of the network your provider is connected to */ public setProvider(provider: Web3Provider, networkId: number): void { - this._web3Wrapper.setProvider(provider, networkId); + this._web3Wrapper.setProvider(provider); (this.exchange as any)._invalidateContractInstances(); + (this.exchange as any)._setNetworkId(networkId); (this.tokenRegistry as any)._invalidateContractInstance(); + (this.tokenRegistry as any)._setNetworkId(networkId); (this.token as any)._invalidateContractInstances(); + (this.token as any)._setNetworkId(networkId); (this.proxy as any)._invalidateContractInstance(); + (this.proxy as any)._setNetworkId(networkId); (this.etherToken as any)._invalidateContractInstance(); + (this.etherToken as any)._setNetworkId(networkId); } /** * Get user Ethereum addresses available through the supplied web3 provider available for sending transactions. @@ -288,35 +292,46 @@ export class ZeroEx { * @return Transaction receipt with decoded log args. */ public async awaitTransactionMinedAsync( - txHash: string, pollingIntervalMs = 1000, timeoutMs?: number): Promise<TransactionReceiptWithDecodedLogs> { + txHash: string, + pollingIntervalMs = 1000, + timeoutMs?: number, + ): Promise<TransactionReceiptWithDecodedLogs> { let timeoutExceeded = false; if (timeoutMs) { - setTimeout(() => timeoutExceeded = true, timeoutMs); + setTimeout(() => (timeoutExceeded = true), timeoutMs); } const txReceiptPromise = new Promise( (resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => { - const intervalId = intervalUtils.setAsyncExcludingInterval(async () => { - if (timeoutExceeded) { - intervalUtils.clearAsyncExcludingInterval(intervalId); - return reject(ZeroExError.TransactionMiningTimeout); - } + const intervalId = intervalUtils.setAsyncExcludingInterval( + async () => { + if (timeoutExceeded) { + intervalUtils.clearAsyncExcludingInterval(intervalId); + return reject(ZeroExError.TransactionMiningTimeout); + } - const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash); - if (!_.isNull(transactionReceipt)) { - intervalUtils.clearAsyncExcludingInterval(intervalId); - const logsWithDecodedArgs = _.map( - transactionReceipt.logs, - this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder), - ); - const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = { - ...transactionReceipt, - logs: logsWithDecodedArgs, - }; - resolve(transactionReceiptWithDecodedLogArgs); - } - }, pollingIntervalMs); - }); + const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash); + if (!_.isNull(transactionReceipt)) { + intervalUtils.clearAsyncExcludingInterval(intervalId); + const logsWithDecodedArgs = _.map( + transactionReceipt.logs, + this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder), + ); + const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = { + ...transactionReceipt, + logs: logsWithDecodedArgs, + }; + resolve(transactionReceiptWithDecodedLogArgs); + } + }, + pollingIntervalMs, + (err: Error) => { + intervalUtils.clearAsyncExcludingInterval(intervalId); + reject(err); + }, + ); + }, + ); return txReceiptPromise; } diff --git a/packages/0x.js/src/artifacts.ts b/packages/0x.js/src/artifacts.ts index de2030812..cbacd7d56 100644 --- a/packages/0x.js/src/artifacts.ts +++ b/packages/0x.js/src/artifacts.ts @@ -1,16 +1,18 @@ +import * as DummyTokenArtifact from './artifacts/DummyToken.json'; import * as EtherTokenArtifact from './artifacts/EtherToken.json'; import * as ExchangeArtifact from './artifacts/Exchange.json'; import * as TokenArtifact from './artifacts/Token.json'; import * as TokenRegistryArtifact from './artifacts/TokenRegistry.json'; import * as TokenTransferProxyArtifact from './artifacts/TokenTransferProxy.json'; import * as ZRXArtifact from './artifacts/ZRX.json'; -import {Artifact} from './types'; +import { Artifact } from './types'; export const artifacts = { - ZRXArtifact: ZRXArtifact as any as Artifact, - TokenArtifact: TokenArtifact as any as Artifact, - ExchangeArtifact: ExchangeArtifact as any as Artifact, - EtherTokenArtifact: EtherTokenArtifact as any as Artifact, - TokenRegistryArtifact: TokenRegistryArtifact as any as Artifact, - TokenTransferProxyArtifact: TokenTransferProxyArtifact as any as Artifact, + ZRXArtifact: (ZRXArtifact as any) as Artifact, + DummyTokenArtifact: (DummyTokenArtifact as any) as Artifact, + TokenArtifact: (TokenArtifact as any) as Artifact, + ExchangeArtifact: (ExchangeArtifact as any) as Artifact, + EtherTokenArtifact: (EtherTokenArtifact as any) as Artifact, + TokenRegistryArtifact: (TokenRegistryArtifact as any) as Artifact, + TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as Artifact, }; diff --git a/packages/0x.js/src/artifacts/DummyToken.json b/packages/0x.js/src/artifacts/DummyToken.json new file mode 100644 index 000000000..f64a8cd3d --- /dev/null +++ b/packages/0x.js/src/artifacts/DummyToken.json @@ -0,0 +1,22 @@ +{ + "contract_name": "DummyToken", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_target", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "setBalance", + "outputs": [], + "payable": false, + "type": "function" + } + ] +} diff --git a/packages/0x.js/src/artifacts/EtherToken.json b/packages/0x.js/src/artifacts/EtherToken.json index 8c1d0f499..91fba7f0a 100644 --- a/packages/0x.js/src/artifacts/EtherToken.json +++ b/packages/0x.js/src/artifacts/EtherToken.json @@ -1,250 +1,284 @@ { - "contract_name": "EtherToken", - "abi": [ - { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ + "contract_name": "EtherToken", + "abi": [ { - "name": "_spender", - "type": "address" + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, { - "name": "_from", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "_to", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "amount", - "type": "uint256" - } - ], - "name": "withdraw", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "decimals", - "outputs": [ - { - "name": "", - "type": "uint8" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "type": "function" + }, { - "name": "_to", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ + "constant": false, + "inputs": [], + "name": "deposit", + "outputs": [], + "payable": true, + "type": "function" + }, { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "deposit", - "outputs": [], - "payable": true, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - }, - { - "name": "_spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "payable": true, - "type": "fallback" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "_from", - "type": "address" - }, - { - "indexed": true, - "name": "_to", - "type": "address" - }, - { - "indexed": false, - "name": "_value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "payable": true, + "type": "fallback" + }, { - "indexed": true, - "name": "_owner", - "type": "address" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" }, { - "indexed": true, - "name": "_spender", - "type": "address" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "name": "_spender", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" }, { - "indexed": false, - "name": "_value", - "type": "uint256" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + } + ], + "networks": { + "1": { + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + }, + "3": { + "address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a" + }, + "42": { + "address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1" + }, + "50": { + "address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c" } - ], - "name": "Approval", - "type": "event" - } - ], - "networks": { - "1": { - "address": "0x2956356cd2a2bf3202f771f50d3d14a367b48070" - }, - "3": { - "address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a" - }, - "42": { - "address": "0x05d090b51c40b020eab3bfcb6a2dff130df22e9c" - }, - "50": { - "address": "0x48bacb9266a570d521063ef5dd96e61686dbe788" } - } } diff --git a/packages/0x.js/src/artifacts/Exchange.json b/packages/0x.js/src/artifacts/Exchange.json index 25495a041..45e277c45 100644 --- a/packages/0x.js/src/artifacts/Exchange.json +++ b/packages/0x.js/src/artifacts/Exchange.json @@ -1,607 +1,607 @@ { - "contract_name": "Exchange", - "abi": [ - { - "constant": true, - "inputs": [ - { - "name": "numerator", - "type": "uint256" - }, - { - "name": "denominator", - "type": "uint256" - }, - { - "name": "target", - "type": "uint256" - } - ], - "name": "isRoundingError", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "filled", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "cancelled", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5][]" - }, - { - "name": "orderValues", - "type": "uint256[6][]" - }, - { - "name": "fillTakerTokenAmount", - "type": "uint256" - }, - { - "name": "shouldThrowOnInsufficientBalanceOrAllowance", - "type": "bool" - }, - { - "name": "v", - "type": "uint8[]" - }, - { - "name": "r", - "type": "bytes32[]" - }, - { - "name": "s", - "type": "bytes32[]" - } - ], - "name": "fillOrdersUpTo", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5]" - }, - { - "name": "orderValues", - "type": "uint256[6]" - }, - { - "name": "cancelTakerTokenAmount", - "type": "uint256" - } - ], - "name": "cancelOrder", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "ZRX_TOKEN_CONTRACT", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5][]" - }, - { - "name": "orderValues", - "type": "uint256[6][]" - }, - { - "name": "fillTakerTokenAmounts", - "type": "uint256[]" - }, - { - "name": "v", - "type": "uint8[]" - }, - { - "name": "r", - "type": "bytes32[]" - }, - { - "name": "s", - "type": "bytes32[]" - } - ], - "name": "batchFillOrKillOrders", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5]" - }, - { - "name": "orderValues", - "type": "uint256[6]" - }, - { - "name": "fillTakerTokenAmount", - "type": "uint256" - }, - { - "name": "v", - "type": "uint8" - }, - { - "name": "r", - "type": "bytes32" - }, - { - "name": "s", - "type": "bytes32" - } - ], - "name": "fillOrKillOrder", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "orderHash", - "type": "bytes32" - } - ], - "name": "getUnavailableTakerTokenAmount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "signer", - "type": "address" - }, - { - "name": "hash", - "type": "bytes32" - }, - { - "name": "v", - "type": "uint8" - }, - { - "name": "r", - "type": "bytes32" - }, - { - "name": "s", - "type": "bytes32" - } - ], - "name": "isValidSignature", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "numerator", - "type": "uint256" - }, - { - "name": "denominator", - "type": "uint256" - }, - { - "name": "target", - "type": "uint256" - } - ], - "name": "getPartialAmount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "TOKEN_TRANSFER_PROXY_CONTRACT", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5][]" - }, - { - "name": "orderValues", - "type": "uint256[6][]" - }, - { - "name": "fillTakerTokenAmounts", - "type": "uint256[]" - }, - { - "name": "shouldThrowOnInsufficientBalanceOrAllowance", - "type": "bool" - }, - { - "name": "v", - "type": "uint8[]" - }, - { - "name": "r", - "type": "bytes32[]" - }, - { - "name": "s", - "type": "bytes32[]" - } - ], - "name": "batchFillOrders", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5][]" - }, - { - "name": "orderValues", - "type": "uint256[6][]" - }, - { - "name": "cancelTakerTokenAmounts", - "type": "uint256[]" - } - ], - "name": "batchCancelOrders", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5]" - }, - { - "name": "orderValues", - "type": "uint256[6]" - }, - { - "name": "fillTakerTokenAmount", - "type": "uint256" - }, - { - "name": "shouldThrowOnInsufficientBalanceOrAllowance", - "type": "bool" - }, - { - "name": "v", - "type": "uint8" - }, - { - "name": "r", - "type": "bytes32" - }, - { - "name": "s", - "type": "bytes32" - } - ], - "name": "fillOrder", - "outputs": [ - { - "name": "filledTakerTokenAmount", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "orderAddresses", - "type": "address[5]" - }, - { - "name": "orderValues", - "type": "uint256[6]" - } - ], - "name": "getOrderHash", - "outputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "EXTERNAL_QUERY_GAS_LIMIT", - "outputs": [ - { - "name": "", - "type": "uint16" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "VERSION", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "type": "function" - }, - { - "inputs": [ - { - "name": "_zrxToken", - "type": "address" - }, - { - "name": "_tokenTransferProxy", - "type": "address" - } - ], - "payable": false, - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "maker", - "type": "address" - }, - { - "indexed": false, - "name": "taker", - "type": "address" - }, - { - "indexed": true, - "name": "feeRecipient", - "type": "address" - }, - { - "indexed": false, - "name": "makerToken", - "type": "address" - }, - { - "indexed": false, - "name": "takerToken", - "type": "address" - }, - { - "indexed": false, - "name": "filledMakerTokenAmount", - "type": "uint256" - }, - { - "indexed": false, - "name": "filledTakerTokenAmount", - "type": "uint256" - }, - { - "indexed": false, - "name": "paidMakerFee", - "type": "uint256" - }, - { - "indexed": false, - "name": "paidTakerFee", - "type": "uint256" - }, - { - "indexed": true, - "name": "tokens", - "type": "bytes32" - }, - { - "indexed": false, - "name": "orderHash", - "type": "bytes32" + "contract_name": "Exchange", + "abi": [ + { + "constant": true, + "inputs": [ + { + "name": "numerator", + "type": "uint256" + }, + { + "name": "denominator", + "type": "uint256" + }, + { + "name": "target", + "type": "uint256" + } + ], + "name": "isRoundingError", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "filled", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "cancelled", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "fillTakerTokenAmount", + "type": "uint256" + }, + { + "name": "shouldThrowOnInsufficientBalanceOrAllowance", + "type": "bool" + }, + { + "name": "v", + "type": "uint8[]" + }, + { + "name": "r", + "type": "bytes32[]" + }, + { + "name": "s", + "type": "bytes32[]" + } + ], + "name": "fillOrdersUpTo", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + }, + { + "name": "cancelTakerTokenAmount", + "type": "uint256" + } + ], + "name": "cancelOrder", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ZRX_TOKEN_CONTRACT", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "fillTakerTokenAmounts", + "type": "uint256[]" + }, + { + "name": "v", + "type": "uint8[]" + }, + { + "name": "r", + "type": "bytes32[]" + }, + { + "name": "s", + "type": "bytes32[]" + } + ], + "name": "batchFillOrKillOrders", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + }, + { + "name": "fillTakerTokenAmount", + "type": "uint256" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "fillOrKillOrder", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "getUnavailableTakerTokenAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "signer", + "type": "address" + }, + { + "name": "hash", + "type": "bytes32" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "numerator", + "type": "uint256" + }, + { + "name": "denominator", + "type": "uint256" + }, + { + "name": "target", + "type": "uint256" + } + ], + "name": "getPartialAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "TOKEN_TRANSFER_PROXY_CONTRACT", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "fillTakerTokenAmounts", + "type": "uint256[]" + }, + { + "name": "shouldThrowOnInsufficientBalanceOrAllowance", + "type": "bool" + }, + { + "name": "v", + "type": "uint8[]" + }, + { + "name": "r", + "type": "bytes32[]" + }, + { + "name": "s", + "type": "bytes32[]" + } + ], + "name": "batchFillOrders", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "cancelTakerTokenAmounts", + "type": "uint256[]" + } + ], + "name": "batchCancelOrders", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + }, + { + "name": "fillTakerTokenAmount", + "type": "uint256" + }, + { + "name": "shouldThrowOnInsufficientBalanceOrAllowance", + "type": "bool" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "fillOrder", + "outputs": [ + { + "name": "filledTakerTokenAmount", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + } + ], + "name": "getOrderHash", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXTERNAL_QUERY_GAS_LIMIT", + "outputs": [ + { + "name": "", + "type": "uint16" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "type": "function" + }, + { + "inputs": [ + { + "name": "_zrxToken", + "type": "address" + }, + { + "name": "_tokenTransferProxy", + "type": "address" + } + ], + "payable": false, + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "maker", + "type": "address" + }, + { + "indexed": false, + "name": "taker", + "type": "address" + }, + { + "indexed": true, + "name": "feeRecipient", + "type": "address" + }, + { + "indexed": false, + "name": "makerToken", + "type": "address" + }, + { + "indexed": false, + "name": "takerToken", + "type": "address" + }, + { + "indexed": false, + "name": "filledMakerTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "filledTakerTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "paidMakerFee", + "type": "uint256" + }, + { + "indexed": false, + "name": "paidTakerFee", + "type": "uint256" + }, + { + "indexed": true, + "name": "tokens", + "type": "bytes32" + }, + { + "indexed": false, + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "LogFill", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "maker", + "type": "address" + }, + { + "indexed": true, + "name": "feeRecipient", + "type": "address" + }, + { + "indexed": false, + "name": "makerToken", + "type": "address" + }, + { + "indexed": false, + "name": "takerToken", + "type": "address" + }, + { + "indexed": false, + "name": "cancelledMakerTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cancelledTakerTokenAmount", + "type": "uint256" + }, + { + "indexed": true, + "name": "tokens", + "type": "bytes32" + }, + { + "indexed": false, + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "LogCancel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "errorId", + "type": "uint8" + }, + { + "indexed": true, + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "LogError", + "type": "event" + } + ], + "networks": { + "1": { + "address": "0x12459c951127e0c374ff9105dda097662a027093" + }, + "3": { + "address": "0x479cc461fecd078f766ecc58533d6f69580cf3ac" + }, + "42": { + "address": "0x90fe2af704b34e0224bf2299c838e04d4dcf1364" + }, + "50": { + "address": "0x48bacb9266a570d521063ef5dd96e61686dbe788" } - ], - "name": "LogFill", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "maker", - "type": "address" - }, - { - "indexed": true, - "name": "feeRecipient", - "type": "address" - }, - { - "indexed": false, - "name": "makerToken", - "type": "address" - }, - { - "indexed": false, - "name": "takerToken", - "type": "address" - }, - { - "indexed": false, - "name": "cancelledMakerTokenAmount", - "type": "uint256" - }, - { - "indexed": false, - "name": "cancelledTakerTokenAmount", - "type": "uint256" - }, - { - "indexed": true, - "name": "tokens", - "type": "bytes32" - }, - { - "indexed": false, - "name": "orderHash", - "type": "bytes32" - } - ], - "name": "LogCancel", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "errorId", - "type": "uint8" - }, - { - "indexed": true, - "name": "orderHash", - "type": "bytes32" - } - ], - "name": "LogError", - "type": "event" - } - ], - "networks": { - "1": { - "address": "0x12459c951127e0c374ff9105dda097662a027093" - }, - "3": { - "address": "0x479cc461fecd078f766ecc58533d6f69580cf3ac" - }, - "42": { - "address": "0x90fe2af704b34e0224bf2299c838e04d4dcf1364" - }, - "50": { - "address": "0xb69e673309512a9d726f87304c6984054f87a93b" } - } } diff --git a/packages/0x.js/src/artifacts/Token.json b/packages/0x.js/src/artifacts/Token.json index a86f8228d..3b5a86ae0 100644 --- a/packages/0x.js/src/artifacts/Token.json +++ b/packages/0x.js/src/artifacts/Token.json @@ -1,172 +1,172 @@ { - "contract_name": "Token", - "abi": [ - { - "constant": false, - "inputs": [ - { - "name": "_spender", - "type": "address" + "contract_name": "Token", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "name": "success", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "supply", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_from", - "type": "address" + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "supply", + "type": "uint256" + } + ], + "payable": false, + "type": "function" }, { - "name": "_to", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "name": "success", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "balance", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_to", - "type": "address" + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "name": "success", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - }, - { - "name": "_spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "name": "remaining", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "_from", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "indexed": true, - "name": "_to", - "type": "address" - }, - { - "indexed": false, - "name": "_value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "_owner", - "type": "address" + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "remaining", + "type": "uint256" + } + ], + "payable": false, + "type": "function" }, { - "indexed": true, - "name": "_spender", - "type": "address" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" }, { - "indexed": false, - "name": "_value", - "type": "uint256" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "name": "_spender", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" } - ], - "name": "Approval", - "type": "event" - } - ] + ] } diff --git a/packages/0x.js/src/artifacts/TokenRegistry.json b/packages/0x.js/src/artifacts/TokenRegistry.json index 973a101e8..81780074c 100644 --- a/packages/0x.js/src/artifacts/TokenRegistry.json +++ b/packages/0x.js/src/artifacts/TokenRegistry.json @@ -1,544 +1,544 @@ { - "contract_name": "TokenRegistry", - "abi": [ - { - "constant": false, - "inputs": [ - { - "name": "_token", - "type": "address" - }, - { - "name": "_index", - "type": "uint256" - } - ], - "name": "removeToken", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_name", - "type": "string" - } - ], - "name": "getTokenAddressByName", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_symbol", - "type": "string" - } - ], - "name": "getTokenAddressBySymbol", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_token", - "type": "address" - }, - { - "name": "_swarmHash", - "type": "bytes" - } - ], - "name": "setTokenSwarmHash", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_token", - "type": "address" - } - ], - "name": "getTokenMetaData", - "outputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "string" - }, - { - "name": "", - "type": "string" - }, - { - "name": "", - "type": "uint8" - }, - { - "name": "", - "type": "bytes" - }, - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_token", - "type": "address" - }, - { - "name": "_name", - "type": "string" - }, - { - "name": "_symbol", - "type": "string" - }, - { - "name": "_decimals", - "type": "uint8" - }, - { - "name": "_ipfsHash", - "type": "bytes" - }, - { - "name": "_swarmHash", - "type": "bytes" - } - ], - "name": "addToken", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_token", - "type": "address" - }, - { - "name": "_name", - "type": "string" - } - ], - "name": "setTokenName", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "tokens", - "outputs": [ - { - "name": "token", - "type": "address" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "symbol", - "type": "string" - }, - { - "name": "decimals", - "type": "uint8" - }, - { - "name": "ipfsHash", - "type": "bytes" - }, - { - "name": "swarmHash", - "type": "bytes" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "tokenAddresses", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_name", - "type": "string" - } - ], - "name": "getTokenByName", - "outputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "string" - }, - { - "name": "", - "type": "string" - }, - { - "name": "", - "type": "uint8" - }, - { - "name": "", - "type": "bytes" - }, - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getTokenAddresses", - "outputs": [ - { - "name": "", - "type": "address[]" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_token", - "type": "address" - }, - { - "name": "_ipfsHash", - "type": "bytes" - } - ], - "name": "setTokenIpfsHash", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_symbol", - "type": "string" - } - ], - "name": "getTokenBySymbol", - "outputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "string" - }, - { - "name": "", - "type": "string" - }, - { - "name": "", - "type": "uint8" - }, - { - "name": "", - "type": "bytes" - }, - { - "name": "", - "type": "bytes" + "contract_name": "TokenRegistry", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_index", + "type": "uint256" + } + ], + "name": "removeToken", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_name", + "type": "string" + } + ], + "name": "getTokenAddressByName", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_symbol", + "type": "string" + } + ], + "name": "getTokenAddressBySymbol", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_swarmHash", + "type": "bytes" + } + ], + "name": "setTokenSwarmHash", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "getTokenMetaData", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "uint8" + }, + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_decimals", + "type": "uint8" + }, + { + "name": "_ipfsHash", + "type": "bytes" + }, + { + "name": "_swarmHash", + "type": "bytes" + } + ], + "name": "addToken", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_name", + "type": "string" + } + ], + "name": "setTokenName", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "tokens", + "outputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "symbol", + "type": "string" + }, + { + "name": "decimals", + "type": "uint8" + }, + { + "name": "ipfsHash", + "type": "bytes" + }, + { + "name": "swarmHash", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "tokenAddresses", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_name", + "type": "string" + } + ], + "name": "getTokenByName", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "uint8" + }, + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getTokenAddresses", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_ipfsHash", + "type": "bytes" + } + ], + "name": "setTokenIpfsHash", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_symbol", + "type": "string" + } + ], + "name": "getTokenBySymbol", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "uint8" + }, + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_symbol", + "type": "string" + } + ], + "name": "setTokenSymbol", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "name", + "type": "string" + }, + { + "indexed": false, + "name": "symbol", + "type": "string" + }, + { + "indexed": false, + "name": "decimals", + "type": "uint8" + }, + { + "indexed": false, + "name": "ipfsHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "swarmHash", + "type": "bytes" + } + ], + "name": "LogAddToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "name", + "type": "string" + }, + { + "indexed": false, + "name": "symbol", + "type": "string" + }, + { + "indexed": false, + "name": "decimals", + "type": "uint8" + }, + { + "indexed": false, + "name": "ipfsHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "swarmHash", + "type": "bytes" + } + ], + "name": "LogRemoveToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldName", + "type": "string" + }, + { + "indexed": false, + "name": "newName", + "type": "string" + } + ], + "name": "LogTokenNameChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldSymbol", + "type": "string" + }, + { + "indexed": false, + "name": "newSymbol", + "type": "string" + } + ], + "name": "LogTokenSymbolChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldIpfsHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "newIpfsHash", + "type": "bytes" + } + ], + "name": "LogTokenIpfsHashChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldSwarmHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "newSwarmHash", + "type": "bytes" + } + ], + "name": "LogTokenSwarmHashChange", + "type": "event" } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_token", - "type": "address" + ], + "networks": { + "1": { + "address": "0x926a74c5c36adf004c87399e65f75628b0f98d2c" }, - { - "name": "_symbol", - "type": "string" - } - ], - "name": "setTokenSymbol", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "token", - "type": "address" + "3": { + "address": "0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed" }, - { - "indexed": false, - "name": "name", - "type": "string" + "42": { + "address": "0xf18e504561f4347bea557f3d4558f559dddbae7f" }, - { - "indexed": false, - "name": "symbol", - "type": "string" - }, - { - "indexed": false, - "name": "decimals", - "type": "uint8" - }, - { - "indexed": false, - "name": "ipfsHash", - "type": "bytes" - }, - { - "indexed": false, - "name": "swarmHash", - "type": "bytes" + "50": { + "address": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082" } - ], - "name": "LogAddToken", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "token", - "type": "address" - }, - { - "indexed": false, - "name": "name", - "type": "string" - }, - { - "indexed": false, - "name": "symbol", - "type": "string" - }, - { - "indexed": false, - "name": "decimals", - "type": "uint8" - }, - { - "indexed": false, - "name": "ipfsHash", - "type": "bytes" - }, - { - "indexed": false, - "name": "swarmHash", - "type": "bytes" - } - ], - "name": "LogRemoveToken", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "token", - "type": "address" - }, - { - "indexed": false, - "name": "oldName", - "type": "string" - }, - { - "indexed": false, - "name": "newName", - "type": "string" - } - ], - "name": "LogTokenNameChange", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "token", - "type": "address" - }, - { - "indexed": false, - "name": "oldSymbol", - "type": "string" - }, - { - "indexed": false, - "name": "newSymbol", - "type": "string" - } - ], - "name": "LogTokenSymbolChange", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "token", - "type": "address" - }, - { - "indexed": false, - "name": "oldIpfsHash", - "type": "bytes" - }, - { - "indexed": false, - "name": "newIpfsHash", - "type": "bytes" - } - ], - "name": "LogTokenIpfsHashChange", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "token", - "type": "address" - }, - { - "indexed": false, - "name": "oldSwarmHash", - "type": "bytes" - }, - { - "indexed": false, - "name": "newSwarmHash", - "type": "bytes" - } - ], - "name": "LogTokenSwarmHashChange", - "type": "event" - } - ], - "networks": { - "1": { - "address": "0x926a74c5c36adf004c87399e65f75628b0f98d2c" - }, - "3": { - "address": "0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed" - }, - "42": { - "address": "0xf18e504561f4347bea557f3d4558f559dddbae7f" - }, - "50": { - "address": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082" } - } } diff --git a/packages/0x.js/src/artifacts/TokenTransferProxy.json b/packages/0x.js/src/artifacts/TokenTransferProxy.json index 065343919..9b6a6cdf9 100644 --- a/packages/0x.js/src/artifacts/TokenTransferProxy.json +++ b/packages/0x.js/src/artifacts/TokenTransferProxy.json @@ -1,184 +1,184 @@ { - "contract_name": "TokenTransferProxy", - "abi": [ - { - "constant": false, - "inputs": [ - { - "name": "token", - "type": "address" + "contract_name": "TokenTransferProxy", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "from", + "type": "address" + }, + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "from", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + } + ], + "name": "addAuthorizedAddress", + "outputs": [], + "payable": false, + "type": "function" }, { - "name": "to", - "type": "address" + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "authorities", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" }, { - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "target", - "type": "address" - } - ], - "name": "addAuthorizedAddress", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "authorities", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "target", - "type": "address" - } - ], - "name": "removeAuthorizedAddress", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + } + ], + "name": "removeAuthorizedAddress", + "outputs": [], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "address" - } - ], - "name": "authorized", - "outputs": [ + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getAuthorizedAddresses", - "outputs": [ + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "authorized", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, { - "name": "", - "type": "address[]" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ + "constant": true, + "inputs": [], + "name": "getAuthorizedAddresses", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "type": "function" + }, { - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "anonymous": false, - "inputs": [ + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "type": "function" + }, { - "indexed": true, - "name": "target", - "type": "address" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": true, + "name": "caller", + "type": "address" + } + ], + "name": "LogAuthorizedAddressAdded", + "type": "event" }, { - "indexed": true, - "name": "caller", - "type": "address" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": true, + "name": "caller", + "type": "address" + } + ], + "name": "LogAuthorizedAddressRemoved", + "type": "event" } - ], - "name": "LogAuthorizedAddressAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "target", - "type": "address" + ], + "networks": { + "1": { + "address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4" }, - { - "indexed": true, - "name": "caller", - "type": "address" + "3": { + "address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6" + }, + "42": { + "address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4" + }, + "50": { + "address": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48" } - ], - "name": "LogAuthorizedAddressRemoved", - "type": "event" } - ], - "networks": { - "1": { - "address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4" - }, - "3": { - "address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6" - }, - "42": { - "address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4" - }, - "50": { - "address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c" - } - } } diff --git a/packages/0x.js/src/artifacts/ZRX.json b/packages/0x.js/src/artifacts/ZRX.json index 7da67fde0..1bd973178 100644 --- a/packages/0x.js/src/artifacts/ZRX.json +++ b/packages/0x.js/src/artifacts/ZRX.json @@ -1,17 +1,17 @@ { - "contract_name": "ZRX", - "networks": { - "1": { - "address": "0xe41d2489571d322189246dafa5ebde1f4699f498" - }, - "3": { - "address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d" - }, - "42": { - "address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570" - }, - "50": { - "address": "0x25b8fe1de9daf8ba351890744ff28cf7dfa8f5e3" + "contract_name": "ZRX", + "networks": { + "1": { + "address": "0xe41d2489571d322189246dafa5ebde1f4699f498" + }, + "3": { + "address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d" + }, + "42": { + "address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570" + }, + "50": { + "address": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401" + } } - } } diff --git a/packages/0x.js/src/bignumber_config.ts b/packages/0x.js/src/bignumber_config.ts deleted file mode 100644 index 2d5214e6f..000000000 --- a/packages/0x.js/src/bignumber_config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import BigNumber from 'bignumber.js'; - -export const bigNumberConfigs = { - configure() { - // By default BigNumber's `toString` method converts to exponential notation if the value has - // more then 20 digits. We want to avoid this behavior, so we set EXPONENTIAL_AT to a high number - BigNumber.config({ - EXPONENTIAL_AT: 1000, - }); - }, -}; diff --git a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts index d56b8632d..27551c01d 100644 --- a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts @@ -1,11 +1,13 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import {Block, BlockAndLogStreamer} from 'ethereumjs-blockstream'; +import { intervalUtils } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream'; import * as _ from 'lodash'; import * as Web3 from 'web3'; import { Artifact, BlockParamLiteral, + BlockRange, ContractEventArgs, ContractEvents, EventCallback, @@ -13,15 +15,15 @@ import { InternalZeroExError, LogWithDecodedArgs, RawLog, - SubscriptionOpts, ZeroExError, } from '../types'; -import {AbiDecoder} from '../utils/abi_decoder'; -import {constants} from '../utils/constants'; -import {filterUtils} from '../utils/filter_utils'; -import {intervalUtils} from '../utils/interval_utils'; +import { AbiDecoder } from '../utils/abi_decoder'; +import { constants } from '../utils/constants'; +import { filterUtils } from '../utils/filter_utils'; -const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = { +const CONTRACT_NAME_TO_NOT_FOUND_ERROR: { + [contractName: string]: ZeroExError; +} = { ZRX: ZeroExError.ZRXContractDoesNotExist, EtherToken: ZeroExError.EtherTokenContractDoesNotExist, Token: ZeroExError.TokenContractDoesNotExist, @@ -34,26 +36,25 @@ export class ContractWrapper { protected _web3Wrapper: Web3Wrapper; private _networkId: number; private _abiDecoder?: AbiDecoder; - private _blockAndLogStreamer: BlockAndLogStreamer|undefined; + private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined; private _blockAndLogStreamInterval: NodeJS.Timer; - private _filters: {[filterToken: string]: Web3.FilterObject}; - private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>}; - private _onLogAddedSubscriptionToken: string|undefined; - private _onLogRemovedSubscriptionToken: string|undefined; + private _filters: { [filterToken: string]: Web3.FilterObject }; + private _filterCallbacks: { + [filterToken: string]: EventCallback<ContractEventArgs>; + }; + private _onLogAddedSubscriptionToken: string | undefined; + private _onLogRemovedSubscriptionToken: string | undefined; constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) { this._web3Wrapper = web3Wrapper; this._networkId = networkId; this._abiDecoder = abiDecoder; this._filters = {}; this._filterCallbacks = {}; - this._blockAndLogStreamer = undefined; + this._blockAndLogStreamerIfExists = undefined; this._onLogAddedSubscriptionToken = undefined; this._onLogRemovedSubscriptionToken = undefined; } - /** - * Cancels all existing subscriptions - */ - public unsubscribeAll(): void { + protected unsubscribeAll(): void { const filterTokens = _.keys(this._filterCallbacks); _.each(filterTokens, filterToken => { this._unsubscribe(filterToken); @@ -74,27 +75,36 @@ export class ContractWrapper { } } protected _subscribe<ArgsType extends ContractEventArgs>( - address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi, - callback: EventCallback<ArgsType>): string { + address: string, + eventName: ContractEvents, + indexFilterValues: IndexedFilterValues, + abi: Web3.ContractAbi, + callback: EventCallback<ArgsType>, + ): string { const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi); - if (_.isUndefined(this._blockAndLogStreamer)) { + if (_.isUndefined(this._blockAndLogStreamerIfExists)) { this._startBlockAndLogStream(); } const filterToken = filterUtils.generateUUID(); this._filters[filterToken] = filter; - this._filterCallbacks[filterToken] = callback; + this._filterCallbacks[filterToken] = callback as EventCallback<ContractEventArgs>; return filterToken; } protected async _getLogsAsync<ArgsType extends ContractEventArgs>( - address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts, - indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> { - const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, subscriptionOpts); + address: string, + eventName: ContractEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + abi: Web3.ContractAbi, + ): Promise<Array<LogWithDecodedArgs<ArgsType>>> { + const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange); const logs = await this._web3Wrapper.getLogsAsync(filter); const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this)); return logsWithDecodedArguments; } protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>( - log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog { + log: Web3.LogEntry, + ): LogWithDecodedArgs<ArgsType> | RawLog { if (_.isUndefined(this._abiDecoder)) { throw new Error(InternalZeroExError.NoAbiDecoder); } @@ -102,7 +112,8 @@ export class ContractWrapper { return logWithDecodedArgs; } protected async _instantiateContractIfExistsAsync( - artifact: Artifact, addressIfExists?: string, + artifact: Artifact, + addressIfExists?: string, ): Promise<Web3.ContractInstance> { let contractAddress: string; if (_.isUndefined(addressIfExists)) { @@ -117,9 +128,7 @@ export class ContractWrapper { if (!doesContractExist) { throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]); } - const contractInstance = this._web3Wrapper.getContractInstance( - artifact.abi, contractAddress, - ); + const contractInstance = this._web3Wrapper.getContractInstance(artifact.abi, contractAddress); return contractInstance; } protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string { @@ -146,45 +155,53 @@ export class ContractWrapper { }); } private _startBlockAndLogStream(): void { - this._blockAndLogStreamer = new BlockAndLogStreamer( + if (!_.isUndefined(this._blockAndLogStreamerIfExists)) { + throw new Error(ZeroExError.SubscriptionAlreadyPresent); + } + this._blockAndLogStreamerIfExists = new BlockAndLogStreamer( this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper), this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper), ); const catchAllLogFilter = {}; - this._blockAndLogStreamer.addLogFilter(catchAllLogFilter); + this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter); this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval( - this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL, + this._reconcileBlockAsync.bind(this), + constants.DEFAULT_BLOCK_POLLING_INTERVAL, + this._onReconcileBlockError.bind(this), ); let isRemoved = false; - this._onLogAddedSubscriptionToken = this._blockAndLogStreamer.subscribeToOnLogAdded( + this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded( this._onLogStateChanged.bind(this, isRemoved), ); isRemoved = true; - this._onLogRemovedSubscriptionToken = this._blockAndLogStreamer.subscribeToOnLogRemoved( + this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved( this._onLogStateChanged.bind(this, isRemoved), ); } + private _onReconcileBlockError(err: Error): void { + const filterTokens = _.keys(this._filterCallbacks); + _.each(filterTokens, filterToken => { + this._unsubscribe(filterToken, err); + }); + } + private _setNetworkId(networkId: number): void { + this._networkId = networkId; + } private _stopBlockAndLogStream(): void { - (this._blockAndLogStreamer as BlockAndLogStreamer).unsubscribeFromOnLogAdded( - this._onLogAddedSubscriptionToken as string); - (this._blockAndLogStreamer as BlockAndLogStreamer).unsubscribeFromOnLogRemoved( - this._onLogRemovedSubscriptionToken as string); + if (_.isUndefined(this._blockAndLogStreamerIfExists)) { + throw new Error(ZeroExError.SubscriptionNotFound); + } + this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string); + this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string); intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamInterval); - delete this._blockAndLogStreamer; + delete this._blockAndLogStreamerIfExists; } private async _reconcileBlockAsync(): Promise<void> { - try { - const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest); - // We need to coerce to Block type cause Web3.Block includes types for mempool blocks - if (!_.isUndefined(this._blockAndLogStreamer)) { - // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined - await this._blockAndLogStreamer.reconcileNewBlock(latestBlock as any as Block); - } - } catch (err) { - const filterTokens = _.keys(this._filterCallbacks); - _.each(filterTokens, filterToken => { - this._unsubscribe(filterToken, err); - }); + const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest); + // 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); } } } diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts index 896cfde3d..b03571636 100644 --- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts @@ -1,40 +1,54 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { schemas } from '@0xproject/json-schemas'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import {artifacts} from '../artifacts'; -import {TransactionOpts, ZeroExError} from '../types'; -import {assert} from '../utils/assert'; +import { artifacts } from '../artifacts'; +import { + BlockRange, + EtherTokenContractEventArgs, + EtherTokenEvents, + EventCallback, + IndexedFilterValues, + LogWithDecodedArgs, + TransactionOpts, + ZeroExError, +} from '../types'; +import { AbiDecoder } from '../utils/abi_decoder'; +import { assert } from '../utils/assert'; -import {ContractWrapper} from './contract_wrapper'; -import {EtherTokenContract} from './generated/ether_token'; -import {TokenWrapper} from './token_wrapper'; +import { ContractWrapper } from './contract_wrapper'; +import { EtherTokenContract } from './generated/ether_token'; +import { TokenWrapper } from './token_wrapper'; /** * 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 { - private _etherTokenContractIfExists?: EtherTokenContract; + private _etherTokenContractsByAddress: { + [address: string]: EtherTokenContract; + } = {}; private _tokenWrapper: TokenWrapper; - private _contractAddressIfExists?: string; - constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenWrapper: TokenWrapper, - contractAddressIfExists?: string) { - super(web3Wrapper, networkId); + constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) { + super(web3Wrapper, networkId, abiDecoder); this._tokenWrapper = tokenWrapper; - this._contractAddressIfExists = contractAddressIfExists; } /** * Deposit ETH into the Wrapped ETH smart contract and issues the equivalent number of wrapped ETH tokens * to the depositor address. These wrapped ETH tokens can be used in 0x trades and are redeemable for 1-to-1 * for ETH. - * @param amountInWei Amount of ETH in Wei the caller wishes to deposit. - * @param depositor The hex encoded user Ethereum address that would like to make the deposit. - * @param txOpts Transaction parameters. + * @param etherTokenAddress EtherToken address you wish to deposit into. + * @param amountInWei Amount of ETH in Wei the caller wishes to deposit. + * @param depositor The hex encoded user Ethereum address that would like to make the deposit. + * @param txOpts Transaction parameters. * @return Transaction hash. */ public async depositAsync( - amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {}, + etherTokenAddress: string, + amountInWei: BigNumber, + depositor: string, + txOpts: TransactionOpts = {}, ): Promise<string> { assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); @@ -42,7 +56,7 @@ export class EtherTokenWrapper extends ContractWrapper { const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(depositor); assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit); - const wethContract = await this._getEtherTokenContractAsync(); + const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress); const txHash = await wethContract.deposit.sendTransactionAsync({ from: depositor, value: amountInWei, @@ -54,22 +68,25 @@ export class EtherTokenWrapper extends ContractWrapper { /** * Withdraw ETH to the withdrawer's address from the wrapped ETH smart contract in exchange for the * equivalent number of wrapped ETH tokens. + * @param etherTokenAddress EtherToken address you wish to withdraw from. * @param amountInWei Amount of ETH in Wei the caller wishes to withdraw. * @param withdrawer The hex encoded user Ethereum address that would like to make the withdrawl. * @param txOpts Transaction parameters. * @return Transaction hash. */ public async withdrawAsync( - amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {}, + etherTokenAddress: string, + amountInWei: BigNumber, + withdrawer: string, + txOpts: TransactionOpts = {}, ): Promise<string> { assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); - const wethContractAddress = this.getContractAddress(); - const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(wethContractAddress, withdrawer); + const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(etherTokenAddress, withdrawer); assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal); - const wethContract = await this._getEtherTokenContractAsync(); + const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress); const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, { from: withdrawer, gas: txOpts.gasLimit, @@ -78,27 +95,90 @@ export class EtherTokenWrapper extends ContractWrapper { return txHash; } /** - * Retrieves the Wrapped Ether token contract address - * @return The Wrapped Ether token contract address + * Gets historical logs without creating a subscription + * @param etherTokenAddress An address of the ether token that emmited the logs. + * @param eventName The ether token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}` + * @return Array of logs that match the parameters */ - public getContractAddress(): string { - const contractAddress = this._getContractAddress( - artifacts.EtherTokenArtifact, this._contractAddressIfExists, + public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>( + etherTokenAddress: string, + eventName: EtherTokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise<Array<LogWithDecodedArgs<ArgsType>>> { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._getLogsAsync<ArgsType>( + etherTokenAddress, + eventName, + blockRange, + indexFilterValues, + artifacts.EtherTokenArtifact.abi, ); - return contractAddress; + return logs; + } + /** + * Subscribe to an event type emitted by the Token contract. + * @param etherTokenAddress The hex encoded address where the ether token is deployed. + * @param eventName The ether token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @return Subscription token used later to unsubscribe + */ + public subscribe<ArgsType extends EtherTokenContractEventArgs>( + etherTokenAddress: string, + eventName: EtherTokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback<ArgsType>, + ): string { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscribe<ArgsType>( + etherTokenAddress, + eventName, + indexFilterValues, + artifacts.EtherTokenArtifact.abi, + callback, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super.unsubscribeAll(); } private _invalidateContractInstance(): void { - delete this._etherTokenContractIfExists; + this.unsubscribeAll(); + this._etherTokenContractsByAddress = {}; } - private async _getEtherTokenContractAsync(): Promise<EtherTokenContract> { - if (!_.isUndefined(this._etherTokenContractIfExists)) { - return this._etherTokenContractIfExists; + private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<EtherTokenContract> { + let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress]; + if (!_.isUndefined(etherTokenContract)) { + return etherTokenContract; } const web3ContractInstance = await this._instantiateContractIfExistsAsync( - artifacts.EtherTokenArtifact, this._contractAddressIfExists, + artifacts.EtherTokenArtifact, + etherTokenAddress, ); const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); - this._etherTokenContractIfExists = contractInstance; - return this._etherTokenContractIfExists; + etherTokenContract = contractInstance; + this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract; + return etherTokenContract; } } diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index 1e9865395..2b6117729 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -1,12 +1,13 @@ -import {schemas} from '@0xproject/json-schemas'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { schemas } from '@0xproject/json-schemas'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import {artifacts} from '../artifacts'; +import { artifacts } from '../artifacts'; import { BlockParamLiteral, + BlockRange, DecodedLogArgs, ECSignature, EventCallback, @@ -15,9 +16,7 @@ import { ExchangeContractEventArgs, ExchangeEvents, IndexedFilterValues, - LogCancelContractEventArgs, LogErrorContractEventArgs, - LogFillContractEventArgs, LogWithDecodedArgs, MethodOpts, Order, @@ -26,21 +25,19 @@ import { OrderFillRequest, OrderTransactionOpts, OrderValues, - RawLog, SignedOrder, - SubscriptionOpts, ValidateOrderFillableOpts, } from '../types'; -import {AbiDecoder} from '../utils/abi_decoder'; -import {assert} from '../utils/assert'; -import {decorators} from '../utils/decorators'; -import {ExchangeTransferSimulator} from '../utils/exchange_transfer_simulator'; -import {OrderValidationUtils} from '../utils/order_validation_utils'; -import {utils} from '../utils/utils'; +import { AbiDecoder } from '../utils/abi_decoder'; +import { assert } from '../utils/assert'; +import { decorators } from '../utils/decorators'; +import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator'; +import { OrderValidationUtils } from '../utils/order_validation_utils'; +import { utils } from '../utils/utils'; -import {ContractWrapper} from './contract_wrapper'; -import {ExchangeContract} from './generated/exchange'; -import {TokenWrapper} from './token_wrapper'; +import { ContractWrapper } from './contract_wrapper'; +import { ExchangeContract } from './generated/exchange'; +import { TokenWrapper } from './token_wrapper'; const SHOULD_VALIDATE_BY_DEFAULT = true; @@ -84,12 +81,19 @@ export class ExchangeWrapper extends ContractWrapper { ]; return [orderAddresses, orderValues]; } - constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, - tokenWrapper: TokenWrapper, contractAddressIfExists?: string) { + constructor( + web3Wrapper: Web3Wrapper, + networkId: number, + abiDecoder: AbiDecoder, + tokenWrapper: TokenWrapper, + contractAddressIfExists?: string, + zrxContractAddressIfExists?: string, + ) { super(web3Wrapper, networkId, abiDecoder); this._tokenWrapper = tokenWrapper; - this._orderValidationUtils = new OrderValidationUtils(tokenWrapper, this); + this._orderValidationUtils = new OrderValidationUtils(this); this._contractAddressIfExists = contractAddressIfExists; + this._zrxContractAddressIfExists = zrxContractAddressIfExists; } /** * Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total @@ -100,14 +104,14 @@ export class ExchangeWrapper extends ContractWrapper { * @param methodOpts Optional arguments this method accepts. * @return The amount of the order (in taker tokens) that has either been filled or cancelled. */ - public async getUnavailableTakerAmountAsync(orderHash: string, - methodOpts?: MethodOpts): Promise<BigNumber> { + public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> { assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); const exchangeContract = await this._getExchangeContractAsync(); const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync( - orderHash, defaultBlock, + orderHash, + defaultBlock, ); // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount); @@ -165,25 +169,33 @@ export class ExchangeWrapper extends ContractWrapper { * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { + @decorators.asyncZeroExErrorHandler + public async fillOrderAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const exchangeInstance = await this._getExchangeContractAsync(); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, + ); } const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder); @@ -221,31 +233,45 @@ export class ExchangeWrapper extends ContractWrapper { * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { + @decorators.asyncZeroExErrorHandler + public async fillOrdersUpToAsync( + signedOrders: SignedOrder[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress); - assert.hasAtMostOneUniqueValue(takerTokenAddresses, - ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed); + assert.hasAtMostOneUniqueValue( + takerTokenAddresses, + ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed, + ); const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress); - assert.hasAtMostOneUniqueValue(exchangeContractAddresses, - ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { + let filledTakerTokenAmount = new BigNumber(0); const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); for (const signedOrder of signedOrders) { - await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); + const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount.minus(filledTakerTokenAmount), + takerAddress, + zrxTokenAddress, + ); + filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount); } } @@ -302,30 +328,37 @@ export class ExchangeWrapper extends ContractWrapper { * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { + @decorators.asyncZeroExErrorHandler + public async batchFillOrdersAsync( + orderFillRequests: OrderFillRequest[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); const exchangeContractAddresses = _.map( orderFillRequests, orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, ); - assert.hasAtMostOneUniqueValue(exchangeContractAddresses, - ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); for (const orderFillRequest of orderFillRequests) { await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, - takerAddress, zrxTokenAddress, + exchangeTradeEmulator, + orderFillRequest.signedOrder, + orderFillRequest.takerTokenFillAmount, + takerAddress, + zrxTokenAddress, ); } } @@ -375,24 +408,32 @@ export class ExchangeWrapper extends ContractWrapper { * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { + @decorators.asyncZeroExErrorHandler + public async fillOrKillOrderAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const exchangeInstance = await this._getExchangeContractAsync(); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, + ); } const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder); @@ -420,34 +461,40 @@ export class ExchangeWrapper extends ContractWrapper { * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[], - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { - assert.doesConformToSchema('orderFillRequests', orderFillRequests, - schemas.orderFillRequestsSchema); + @decorators.asyncZeroExErrorHandler + public async batchFillOrKillAsync( + orderFillRequests: OrderFillRequest[], + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { + assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); const exchangeContractAddresses = _.map( orderFillRequests, orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, ); - assert.hasAtMostOneUniqueValue(exchangeContractAddresses, - ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); if (_.isEmpty(orderFillRequests)) { throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); } const exchangeInstance = await this._getExchangeContractAsync(); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); for (const orderFillRequest of orderFillRequests) { await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, - takerAddress, zrxTokenAddress, + exchangeTradeEmulator, + orderFillRequest.signedOrder, + orderFillRequest.takerTokenFillAmount, + takerAddress, + zrxTokenAddress, ); } } @@ -463,8 +510,9 @@ export class ExchangeWrapper extends ContractWrapper { }); // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'( - const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = - _.unzip<any>(orderAddressesValuesAndTakerTokenFillAmounts); + const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>( + orderAddressesValuesAndTakerTokenFillAmounts, + ); const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync( orderAddresses, orderValues, @@ -488,24 +536,29 @@ export class ExchangeWrapper extends ContractWrapper { * @param transactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async cancelOrderAsync(order: Order|SignedOrder, - cancelTakerTokenAmount: BigNumber, - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { + @decorators.asyncZeroExErrorHandler + public async cancelOrderAsync( + order: Order | SignedOrder, + cancelTakerTokenAmount: BigNumber, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { assert.doesConformToSchema('order', order, schemas.orderSchema); assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount); await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper); const exchangeInstance = await this._getExchangeContractAsync(); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { const orderHash = utils.getOrderHashHex(order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); OrderValidationUtils.validateCancelOrderThrowIfInvalid( - order, cancelTakerTokenAmount, unavailableTakerTokenAmount); + order, + cancelTakerTokenAmount, + unavailableTakerTokenAmount, + ); } const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order); @@ -529,34 +582,41 @@ export class ExchangeWrapper extends ContractWrapper { * @param transactionOpts Optional arguments this method accepts. * @return Transaction hash. */ - @decorators.contractCallErrorHandler - public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[], - orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { - assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests, - schemas.orderCancellationRequestsSchema); + @decorators.asyncZeroExErrorHandler + public async batchCancelOrdersAsync( + orderCancellationRequests: OrderCancellationRequest[], + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise<string> { + assert.doesConformToSchema( + 'orderCancellationRequests', + orderCancellationRequests, + schemas.orderCancellationRequestsSchema, + ); const exchangeContractAddresses = _.map( orderCancellationRequests, orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress, ); - assert.hasAtMostOneUniqueValue(exchangeContractAddresses, - ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker); assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); const maker = makers[0]; await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper); - const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; if (shouldValidate) { for (const orderCancellationRequest of orderCancellationRequests) { const orderHash = utils.getOrderHashHex(orderCancellationRequest.order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); OrderValidationUtils.validateCancelOrderThrowIfInvalid( - orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount, + orderCancellationRequest.order, + orderCancellationRequest.takerTokenCancelAmount, unavailableTakerTokenAmount, ); } - } if (_.isEmpty(orderCancellationRequests)) { throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); @@ -569,8 +629,9 @@ export class ExchangeWrapper extends ContractWrapper { ]; }); // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'( - const [orderAddresses, orderValues, cancelTakerTokenAmounts] = - _.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts); + const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>( + orderAddressesValuesAndTakerTokenCancelAmounts, + ); const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync( orderAddresses, orderValues, @@ -592,14 +653,20 @@ export class ExchangeWrapper extends ContractWrapper { * @return Subscription token used later to unsubscribe */ public subscribe<ArgsType extends ExchangeContractEventArgs>( - eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues, - callback: EventCallback<ArgsType>): string { + eventName: ExchangeEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback<ArgsType>, + ): string { 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, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback, + exchangeContractAddress, + eventName, + indexFilterValues, + artifacts.ExchangeArtifact.abi, + callback, ); return subscriptionToken; } @@ -611,22 +678,34 @@ export class ExchangeWrapper extends ContractWrapper { this._unsubscribe(subscriptionToken); } /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super.unsubscribeAll(); + } + /** * Gets historical logs without creating a subscription * @param eventName The exchange contract event you would like to subscribe to. - * @param subscriptionOpts Subscriptions options that let you configure the subscription. + * @param blockRange Block range to get logs from. * @param indexFilterValues An object where the keys are indexed args returned by the event and * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` * @return Array of logs that match the parameters */ public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>( - eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues, + eventName: ExchangeEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, ): Promise<Array<LogWithDecodedArgs<ArgsType>>> { assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); - assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); const exchangeContractAddress = this.getContractAddress(); const logs = await this._getLogsAsync<ArgsType>( - exchangeContractAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.ExchangeArtifact.abi, + exchangeContractAddress, + eventName, + blockRange, + indexFilterValues, + artifacts.ExchangeArtifact.abi, ); return logs; } @@ -649,14 +728,18 @@ export class ExchangeWrapper extends ContractWrapper { * to validate for. */ public async validateOrderFillableOrThrowAsync( - signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts, + signedOrder: SignedOrder, + opts?: ValidateOrderFillableOpts, ): Promise<void> { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); const zrxTokenAddress = this.getZRXTokenAddress(); const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined; const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateOrderFillableOrThrowAsync( - exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount, + exchangeTradeEmulator, + signedOrder, + zrxTokenAddress, + expectedFillTakerTokenAmount, ); } /** @@ -667,16 +750,23 @@ export class ExchangeWrapper extends ContractWrapper { * @param takerAddress The user Ethereum address who would like to fill this order. * Must be available via the supplied Web3.Provider passed to 0x.js. */ - public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - takerAddress: string): Promise<void> { + public async validateFillOrderThrowIfInvalidAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + ): Promise<void> { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, + ); } /** * Checks if cancelling a given order will succeed and throws an informative error if it won't. @@ -685,13 +775,18 @@ export class ExchangeWrapper extends ContractWrapper { * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel. */ public async validateCancelOrderThrowIfInvalidAsync( - order: Order, cancelTakerTokenAmount: BigNumber): Promise<void> { + order: Order, + cancelTakerTokenAmount: BigNumber, + ): Promise<void> { assert.doesConformToSchema('order', order, schemas.orderSchema); assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount); const orderHash = utils.getOrderHashHex(order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); OrderValidationUtils.validateCancelOrderThrowIfInvalid( - order, cancelTakerTokenAmount, unavailableTakerTokenAmount); + order, + cancelTakerTokenAmount, + unavailableTakerTokenAmount, + ); } /** * Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't. @@ -701,16 +796,23 @@ export class ExchangeWrapper extends ContractWrapper { * @param takerAddress The user Ethereum address who would like to fill this order. * Must be available via the supplied Web3.Provider passed to 0x.js. */ - public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - takerAddress: string): Promise<void> { + public async validateFillOrKillOrderThrowIfInvalidAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + ): Promise<void> { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, + ); } /** * Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing: @@ -721,15 +823,19 @@ export class ExchangeWrapper extends ContractWrapper { * @param takerTokenAmount The order size on the taker side * @param makerTokenAmount The order size on the maker side */ - public async isRoundingErrorAsync(fillTakerTokenAmount: BigNumber, - takerTokenAmount: BigNumber, - makerTokenAmount: BigNumber): Promise<boolean> { + public async isRoundingErrorAsync( + fillTakerTokenAmount: BigNumber, + takerTokenAmount: BigNumber, + makerTokenAmount: BigNumber, + ): Promise<boolean> { assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount); assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount); const exchangeInstance = await this._getExchangeContractAsync(); const isRoundingError = await exchangeInstance.isRoundingError.callAsync( - fillTakerTokenAmount, takerTokenAmount, makerTokenAmount, + fillTakerTokenAmount, + takerTokenAmount, + makerTokenAmount, ); return isRoundingError; } @@ -737,10 +843,10 @@ export class ExchangeWrapper extends ContractWrapper { * Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure. * @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync` */ - public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>): void { + public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs> | Web3.LogEntry>): void { const errLog = _.find(logs, { event: ExchangeEvents.LogError, - }) as LogWithDecodedArgs<LogErrorContractEventArgs>|undefined; + }) as LogWithDecodedArgs<LogErrorContractEventArgs> | undefined; if (!_.isUndefined(errLog)) { const logArgs = errLog.args; const errCode = logArgs.errorId.toNumber(); @@ -753,17 +859,18 @@ export class ExchangeWrapper extends ContractWrapper { * @return Address of ZRX token */ public getZRXTokenAddress(): string { - const contractAddress = this._getContractAddress( - artifacts.ZRXArtifact, this._zrxContractAddressIfExists, - ); + const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists); return contractAddress; } private _invalidateContractInstances(): void { this.unsubscribeAll(); delete this._exchangeContractIfExists; } - private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature, - signerAddressHex: string): Promise<boolean> { + private async _isValidSignatureUsingContractCallAsync( + dataHex: string, + ecSignature: ECSignature, + signerAddressHex: string, + ): Promise<boolean> { assert.isHexString('dataHex', dataHex); assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema); assert.isETHAddressHex('signerAddressHex', signerAddressHex); @@ -779,7 +886,7 @@ export class ExchangeWrapper extends ContractWrapper { ); return isValidSignature; } - private async _getOrderHashHexUsingContractCallAsync(order: Order|SignedOrder): Promise<string> { + private async _getOrderHashHexUsingContractCallAsync(order: Order | SignedOrder): Promise<string> { const exchangeInstance = await this._getExchangeContractAsync(); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order); const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues); @@ -790,7 +897,8 @@ export class ExchangeWrapper extends ContractWrapper { return this._exchangeContractIfExists; } const web3ContractInstance = await this._instantiateContractIfExistsAsync( - artifacts.ExchangeArtifact, this._contractAddressIfExists, + artifacts.ExchangeArtifact, + this._contractAddressIfExists, ); const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); this._exchangeContractIfExists = contractInstance; diff --git a/packages/0x.js/src/contract_wrappers/generated/.gitignore b/packages/0x.js/src/contract_wrappers/generated/.gitignore new file mode 100644 index 000000000..834808b48 --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/.gitignore @@ -0,0 +1,6 @@ +dummy_token.ts +ether_token.ts +exchange.ts +token_registry.ts +token_transfer_proxy.ts +token.ts diff --git a/packages/0x.js/src/contract_wrappers/generated/base_contract.ts b/packages/0x.js/src/contract_wrappers/generated/base_contract.ts index 396a4d593..28a7e2f52 100644 --- a/packages/0x.js/src/contract_wrappers/generated/base_contract.ts +++ b/packages/0x.js/src/contract_wrappers/generated/base_contract.ts @@ -1,8 +1,7 @@ +import {TxData, TxDataPayable} from '@0xproject/types'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import {TxData, TxDataPayable} from '../../types'; - export class BaseContract { protected web3ContractInstance: Web3.ContractInstance; protected defaults: Partial<TxData>; diff --git a/packages/0x.js/src/contract_wrappers/generated/ether_token.ts b/packages/0x.js/src/contract_wrappers/generated/ether_token.ts deleted file mode 100644 index ce3f9f527..000000000 --- a/packages/0x.js/src/contract_wrappers/generated/ether_token.ts +++ /dev/null @@ -1,363 +0,0 @@ -/** - * This file is auto-generated using abi-gen. Don't edit directly. - * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. - */ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; -import * as Web3 from 'web3'; - -import {TxData, TxDataPayable} from '../../types'; -import {classUtils} from '../../utils/class_utils'; - -import {BaseContract} from './base_contract'; - -export class EtherTokenContract extends BaseContract { - public name = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as EtherTokenContract; - const result = await promisify<string - >( - self.web3ContractInstance.name.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public approve = { - async sendTransactionAsync( - _spender: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.approve.estimateGasAsync.bind( - self, - _spender, - _value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.approve, self.web3ContractInstance, - )( - _spender, - _value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _spender: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.approve.estimateGas, self.web3ContractInstance, - )( - _spender, - _value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _spender: string, - _value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as EtherTokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.approve.getData(); - return abiEncodedTransactionData; - }, - }; - public totalSupply = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as EtherTokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.totalSupply.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public transferFrom = { - async sendTransactionAsync( - _from: string, - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transferFrom.estimateGasAsync.bind( - self, - _from, - _to, - _value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transferFrom, self.web3ContractInstance, - )( - _from, - _to, - _value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _from: string, - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transferFrom.estimateGas, self.web3ContractInstance, - )( - _from, - _to, - _value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _from: string, - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as EtherTokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.transferFrom.getData(); - return abiEncodedTransactionData; - }, - }; - public withdraw = { - async sendTransactionAsync( - amount: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.withdraw.estimateGasAsync.bind( - self, - amount, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.withdraw, self.web3ContractInstance, - )( - amount, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - amount: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.withdraw.estimateGas, self.web3ContractInstance, - )( - amount, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - amount: BigNumber, - txData: TxData = {}, - ): string { - const self = this as EtherTokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.withdraw.getData(); - return abiEncodedTransactionData; - }, - }; - public decimals = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as EtherTokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.decimals.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public balanceOf = { - async callAsync( - _owner: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as EtherTokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.balanceOf.call, - self.web3ContractInstance, - )( - _owner, - ); - return result; - }, - }; - public symbol = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as EtherTokenContract; - const result = await promisify<string - >( - self.web3ContractInstance.symbol.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public transfer = { - async sendTransactionAsync( - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transfer.estimateGasAsync.bind( - self, - _to, - _value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transfer, self.web3ContractInstance, - )( - _to, - _value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transfer.estimateGas, self.web3ContractInstance, - )( - _to, - _value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as EtherTokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.transfer.getData(); - return abiEncodedTransactionData; - }, - }; - public deposit = { - async sendTransactionAsync( - txData: TxDataPayable = {}, - ): Promise<string> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.deposit.estimateGasAsync.bind( - self, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.deposit, self.web3ContractInstance, - )( - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - txData: TxData = {}, - ): Promise<number> { - const self = this as EtherTokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.deposit.estimateGas, self.web3ContractInstance, - )( - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - txData: TxData = {}, - ): string { - const self = this as EtherTokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.deposit.getData(); - return abiEncodedTransactionData; - }, - }; - public allowance = { - async callAsync( - _owner: string, - _spender: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as EtherTokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.allowance.call, - self.web3ContractInstance, - )( - _owner, - _spender, - ); - return result; - }, - }; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { - super(web3ContractInstance, defaults); - classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); - } -} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/exchange.ts b/packages/0x.js/src/contract_wrappers/generated/exchange.ts deleted file mode 100644 index e06ed960c..000000000 --- a/packages/0x.js/src/contract_wrappers/generated/exchange.ts +++ /dev/null @@ -1,730 +0,0 @@ -/** - * This file is auto-generated using abi-gen. Don't edit directly. - * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. - */ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; -import * as Web3 from 'web3'; - -import {TxData, TxDataPayable} from '../../types'; -import {classUtils} from '../../utils/class_utils'; - -import {BaseContract} from './base_contract'; - -export class ExchangeContract extends BaseContract { - public isRoundingError = { - async callAsync( - numerator: BigNumber, - denominator: BigNumber, - target: BigNumber, - defaultBlock?: Web3.BlockParam, - ): Promise<boolean - > { - const self = this as ExchangeContract; - const result = await promisify<boolean - >( - self.web3ContractInstance.isRoundingError.call, - self.web3ContractInstance, - )( - numerator, - denominator, - target, - ); - return result; - }, - }; - public filled = { - async callAsync( - index: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as ExchangeContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.filled.call, - self.web3ContractInstance, - )( - index, - ); - return result; - }, - }; - public cancelled = { - async callAsync( - index: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as ExchangeContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.cancelled.call, - self.web3ContractInstance, - )( - index, - ); - return result; - }, - }; - public fillOrdersUpTo = { - async sendTransactionAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.fillOrdersUpTo.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.fillOrdersUpTo, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.fillOrdersUpTo.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.fillOrdersUpTo.getData(); - return abiEncodedTransactionData; - }, - }; - public cancelOrder = { - async sendTransactionAsync( - orderAddresses: string[], - orderValues: BigNumber[], - cancelTakerTokenAmount: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.cancelOrder.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - cancelTakerTokenAmount, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.cancelOrder, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - cancelTakerTokenAmount, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[], - orderValues: BigNumber[], - cancelTakerTokenAmount: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.cancelOrder.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - cancelTakerTokenAmount, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[], - orderValues: BigNumber[], - cancelTakerTokenAmount: BigNumber, - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.cancelOrder.getData(); - return abiEncodedTransactionData; - }, - }; - public ZRX_TOKEN_CONTRACT = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as ExchangeContract; - const result = await promisify<string - >( - self.web3ContractInstance.ZRX_TOKEN_CONTRACT.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public batchFillOrKillOrders = { - async sendTransactionAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmounts: BigNumber[], - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.batchFillOrKillOrders.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - fillTakerTokenAmounts, - v, - r, - s, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.batchFillOrKillOrders, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmounts, - v, - r, - s, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmounts: BigNumber[], - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.batchFillOrKillOrders.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmounts, - v, - r, - s, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmounts: BigNumber[], - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.batchFillOrKillOrders.getData(); - return abiEncodedTransactionData; - }, - }; - public fillOrKillOrder = { - async sendTransactionAsync( - orderAddresses: string[], - orderValues: BigNumber[], - fillTakerTokenAmount: BigNumber, - v: number|BigNumber, - r: string, - s: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.fillOrKillOrder.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - fillTakerTokenAmount, - v, - r, - s, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.fillOrKillOrder, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmount, - v, - r, - s, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[], - orderValues: BigNumber[], - fillTakerTokenAmount: BigNumber, - v: number|BigNumber, - r: string, - s: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.fillOrKillOrder.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmount, - v, - r, - s, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[], - orderValues: BigNumber[], - fillTakerTokenAmount: BigNumber, - v: number|BigNumber, - r: string, - s: string, - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.fillOrKillOrder.getData(); - return abiEncodedTransactionData; - }, - }; - public getUnavailableTakerTokenAmount = { - async callAsync( - orderHash: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as ExchangeContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.getUnavailableTakerTokenAmount.call, - self.web3ContractInstance, - )( - orderHash, - ); - return result; - }, - }; - public isValidSignature = { - async callAsync( - signer: string, - hash: string, - v: number|BigNumber, - r: string, - s: string, - defaultBlock?: Web3.BlockParam, - ): Promise<boolean - > { - const self = this as ExchangeContract; - const result = await promisify<boolean - >( - self.web3ContractInstance.isValidSignature.call, - self.web3ContractInstance, - )( - signer, - hash, - v, - r, - s, - ); - return result; - }, - }; - public getPartialAmount = { - async callAsync( - numerator: BigNumber, - denominator: BigNumber, - target: BigNumber, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as ExchangeContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.getPartialAmount.call, - self.web3ContractInstance, - )( - numerator, - denominator, - target, - ); - return result; - }, - }; - public TOKEN_TRANSFER_PROXY_CONTRACT = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as ExchangeContract; - const result = await promisify<string - >( - self.web3ContractInstance.TOKEN_TRANSFER_PROXY_CONTRACT.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public batchFillOrders = { - async sendTransactionAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmounts: BigNumber[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.batchFillOrders.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - fillTakerTokenAmounts, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.batchFillOrders, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmounts, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmounts: BigNumber[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.batchFillOrders.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmounts, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[][], - orderValues: BigNumber[][], - fillTakerTokenAmounts: BigNumber[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber[], - r: string[], - s: string[], - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.batchFillOrders.getData(); - return abiEncodedTransactionData; - }, - }; - public batchCancelOrders = { - async sendTransactionAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - cancelTakerTokenAmounts: BigNumber[], - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.batchCancelOrders.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - cancelTakerTokenAmounts, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.batchCancelOrders, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - cancelTakerTokenAmounts, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[][], - orderValues: BigNumber[][], - cancelTakerTokenAmounts: BigNumber[], - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.batchCancelOrders.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - cancelTakerTokenAmounts, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[][], - orderValues: BigNumber[][], - cancelTakerTokenAmounts: BigNumber[], - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.batchCancelOrders.getData(); - return abiEncodedTransactionData; - }, - }; - public fillOrder = { - async sendTransactionAsync( - orderAddresses: string[], - orderValues: BigNumber[], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber, - r: string, - s: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.fillOrder.estimateGasAsync.bind( - self, - orderAddresses, - orderValues, - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.fillOrder, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - orderAddresses: string[], - orderValues: BigNumber[], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber, - r: string, - s: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as ExchangeContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.fillOrder.estimateGas, self.web3ContractInstance, - )( - orderAddresses, - orderValues, - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - v, - r, - s, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - orderAddresses: string[], - orderValues: BigNumber[], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number|BigNumber, - r: string, - s: string, - txData: TxData = {}, - ): string { - const self = this as ExchangeContract; - const abiEncodedTransactionData = self.web3ContractInstance.fillOrder.getData(); - return abiEncodedTransactionData; - }, - }; - public getOrderHash = { - async callAsync( - orderAddresses: string[], - orderValues: BigNumber[], - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as ExchangeContract; - const result = await promisify<string - >( - self.web3ContractInstance.getOrderHash.call, - self.web3ContractInstance, - )( - orderAddresses, - orderValues, - ); - return result; - }, - }; - public EXTERNAL_QUERY_GAS_LIMIT = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as ExchangeContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.EXTERNAL_QUERY_GAS_LIMIT.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public VERSION = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as ExchangeContract; - const result = await promisify<string - >( - self.web3ContractInstance.VERSION.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { - super(web3ContractInstance, defaults); - classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); - } -} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/token.ts b/packages/0x.js/src/contract_wrappers/generated/token.ts deleted file mode 100644 index 83a4ead34..000000000 --- a/packages/0x.js/src/contract_wrappers/generated/token.ts +++ /dev/null @@ -1,232 +0,0 @@ -/** - * This file is auto-generated using abi-gen. Don't edit directly. - * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. - */ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; -import * as Web3 from 'web3'; - -import {TxData, TxDataPayable} from '../../types'; -import {classUtils} from '../../utils/class_utils'; - -import {BaseContract} from './base_contract'; - -export class TokenContract extends BaseContract { - public approve = { - async sendTransactionAsync( - _spender: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.approve.estimateGasAsync.bind( - self, - _spender, - _value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.approve, self.web3ContractInstance, - )( - _spender, - _value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _spender: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.approve.estimateGas, self.web3ContractInstance, - )( - _spender, - _value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _spender: string, - _value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as TokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.approve.getData(); - return abiEncodedTransactionData; - }, - }; - public totalSupply = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as TokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.totalSupply.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public transferFrom = { - async sendTransactionAsync( - _from: string, - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transferFrom.estimateGasAsync.bind( - self, - _from, - _to, - _value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transferFrom, self.web3ContractInstance, - )( - _from, - _to, - _value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _from: string, - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transferFrom.estimateGas, self.web3ContractInstance, - )( - _from, - _to, - _value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _from: string, - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as TokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.transferFrom.getData(); - return abiEncodedTransactionData; - }, - }; - public balanceOf = { - async callAsync( - _owner: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as TokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.balanceOf.call, - self.web3ContractInstance, - )( - _owner, - ); - return result; - }, - }; - public transfer = { - async sendTransactionAsync( - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transfer.estimateGasAsync.bind( - self, - _to, - _value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transfer, self.web3ContractInstance, - )( - _to, - _value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transfer.estimateGas, self.web3ContractInstance, - )( - _to, - _value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _to: string, - _value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as TokenContract; - const abiEncodedTransactionData = self.web3ContractInstance.transfer.getData(); - return abiEncodedTransactionData; - }, - }; - public allowance = { - async callAsync( - _owner: string, - _spender: string, - defaultBlock?: Web3.BlockParam, - ): Promise<BigNumber - > { - const self = this as TokenContract; - const result = await promisify<BigNumber - >( - self.web3ContractInstance.allowance.call, - self.web3ContractInstance, - )( - _owner, - _spender, - ); - return result; - }, - }; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { - super(web3ContractInstance, defaults); - classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); - } -} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/token_registry.ts b/packages/0x.js/src/contract_wrappers/generated/token_registry.ts deleted file mode 100644 index 5d9ad9016..000000000 --- a/packages/0x.js/src/contract_wrappers/generated/token_registry.ts +++ /dev/null @@ -1,550 +0,0 @@ -/** - * This file is auto-generated using abi-gen. Don't edit directly. - * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. - */ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; -import * as Web3 from 'web3'; - -import {TxData, TxDataPayable} from '../../types'; -import {classUtils} from '../../utils/class_utils'; - -import {BaseContract} from './base_contract'; - -export class TokenRegistryContract extends BaseContract { - public removeToken = { - async sendTransactionAsync( - _token: string, - _index: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.removeToken.estimateGasAsync.bind( - self, - _token, - _index, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.removeToken, self.web3ContractInstance, - )( - _token, - _index, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _token: string, - _index: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.removeToken.estimateGas, self.web3ContractInstance, - )( - _token, - _index, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _token: string, - _index: BigNumber, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.removeToken.getData(); - return abiEncodedTransactionData; - }, - }; - public getTokenAddressByName = { - async callAsync( - _name: string, - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as TokenRegistryContract; - const result = await promisify<string - >( - self.web3ContractInstance.getTokenAddressByName.call, - self.web3ContractInstance, - )( - _name, - ); - return result; - }, - }; - public getTokenAddressBySymbol = { - async callAsync( - _symbol: string, - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as TokenRegistryContract; - const result = await promisify<string - >( - self.web3ContractInstance.getTokenAddressBySymbol.call, - self.web3ContractInstance, - )( - _symbol, - ); - return result; - }, - }; - public setTokenSwarmHash = { - async sendTransactionAsync( - _token: string, - _swarmHash: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.setTokenSwarmHash.estimateGasAsync.bind( - self, - _token, - _swarmHash, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.setTokenSwarmHash, self.web3ContractInstance, - )( - _token, - _swarmHash, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _token: string, - _swarmHash: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.setTokenSwarmHash.estimateGas, self.web3ContractInstance, - )( - _token, - _swarmHash, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _token: string, - _swarmHash: string, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.setTokenSwarmHash.getData(); - return abiEncodedTransactionData; - }, - }; - public getTokenMetaData = { - async callAsync( - _token: string, - defaultBlock?: Web3.BlockParam, - ): Promise<[string, string, string, BigNumber, string, string] - > { - const self = this as TokenRegistryContract; - const result = await promisify<[string, string, string, BigNumber, string, string] - >( - self.web3ContractInstance.getTokenMetaData.call, - self.web3ContractInstance, - )( - _token, - ); - return result; - }, - }; - public owner = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as TokenRegistryContract; - const result = await promisify<string - >( - self.web3ContractInstance.owner.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public addToken = { - async sendTransactionAsync( - _token: string, - _name: string, - _symbol: string, - _decimals: number|BigNumber, - _ipfsHash: string, - _swarmHash: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.addToken.estimateGasAsync.bind( - self, - _token, - _name, - _symbol, - _decimals, - _ipfsHash, - _swarmHash, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.addToken, self.web3ContractInstance, - )( - _token, - _name, - _symbol, - _decimals, - _ipfsHash, - _swarmHash, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _token: string, - _name: string, - _symbol: string, - _decimals: number|BigNumber, - _ipfsHash: string, - _swarmHash: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.addToken.estimateGas, self.web3ContractInstance, - )( - _token, - _name, - _symbol, - _decimals, - _ipfsHash, - _swarmHash, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _token: string, - _name: string, - _symbol: string, - _decimals: number|BigNumber, - _ipfsHash: string, - _swarmHash: string, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.addToken.getData(); - return abiEncodedTransactionData; - }, - }; - public setTokenName = { - async sendTransactionAsync( - _token: string, - _name: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.setTokenName.estimateGasAsync.bind( - self, - _token, - _name, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.setTokenName, self.web3ContractInstance, - )( - _token, - _name, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _token: string, - _name: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.setTokenName.estimateGas, self.web3ContractInstance, - )( - _token, - _name, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _token: string, - _name: string, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.setTokenName.getData(); - return abiEncodedTransactionData; - }, - }; - public tokens = { - async callAsync( - index: string, - defaultBlock?: Web3.BlockParam, - ): Promise<[string, string, string, BigNumber, string, string] - > { - const self = this as TokenRegistryContract; - const result = await promisify<[string, string, string, BigNumber, string, string] - >( - self.web3ContractInstance.tokens.call, - self.web3ContractInstance, - )( - index, - ); - return result; - }, - }; - public tokenAddresses = { - async callAsync( - index: BigNumber, - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as TokenRegistryContract; - const result = await promisify<string - >( - self.web3ContractInstance.tokenAddresses.call, - self.web3ContractInstance, - )( - index, - ); - return result; - }, - }; - public getTokenByName = { - async callAsync( - _name: string, - defaultBlock?: Web3.BlockParam, - ): Promise<[string, string, string, BigNumber, string, string] - > { - const self = this as TokenRegistryContract; - const result = await promisify<[string, string, string, BigNumber, string, string] - >( - self.web3ContractInstance.getTokenByName.call, - self.web3ContractInstance, - )( - _name, - ); - return result; - }, - }; - public getTokenAddresses = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string[] - > { - const self = this as TokenRegistryContract; - const result = await promisify<string[] - >( - self.web3ContractInstance.getTokenAddresses.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public setTokenIpfsHash = { - async sendTransactionAsync( - _token: string, - _ipfsHash: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.setTokenIpfsHash.estimateGasAsync.bind( - self, - _token, - _ipfsHash, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.setTokenIpfsHash, self.web3ContractInstance, - )( - _token, - _ipfsHash, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _token: string, - _ipfsHash: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.setTokenIpfsHash.estimateGas, self.web3ContractInstance, - )( - _token, - _ipfsHash, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _token: string, - _ipfsHash: string, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.setTokenIpfsHash.getData(); - return abiEncodedTransactionData; - }, - }; - public getTokenBySymbol = { - async callAsync( - _symbol: string, - defaultBlock?: Web3.BlockParam, - ): Promise<[string, string, string, BigNumber, string, string] - > { - const self = this as TokenRegistryContract; - const result = await promisify<[string, string, string, BigNumber, string, string] - >( - self.web3ContractInstance.getTokenBySymbol.call, - self.web3ContractInstance, - )( - _symbol, - ); - return result; - }, - }; - public setTokenSymbol = { - async sendTransactionAsync( - _token: string, - _symbol: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.setTokenSymbol.estimateGasAsync.bind( - self, - _token, - _symbol, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.setTokenSymbol, self.web3ContractInstance, - )( - _token, - _symbol, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - _token: string, - _symbol: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.setTokenSymbol.estimateGas, self.web3ContractInstance, - )( - _token, - _symbol, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - _token: string, - _symbol: string, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.setTokenSymbol.getData(); - return abiEncodedTransactionData; - }, - }; - public transferOwnership = { - async sendTransactionAsync( - newOwner: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transferOwnership.estimateGasAsync.bind( - self, - newOwner, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transferOwnership, self.web3ContractInstance, - )( - newOwner, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - newOwner: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenRegistryContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transferOwnership.estimateGas, self.web3ContractInstance, - )( - newOwner, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - newOwner: string, - txData: TxData = {}, - ): string { - const self = this as TokenRegistryContract; - const abiEncodedTransactionData = self.web3ContractInstance.transferOwnership.getData(); - return abiEncodedTransactionData; - }, - }; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { - super(web3ContractInstance, defaults); - classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); - } -} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/token_transfer_proxy.ts b/packages/0x.js/src/contract_wrappers/generated/token_transfer_proxy.ts deleted file mode 100644 index fd50a5894..000000000 --- a/packages/0x.js/src/contract_wrappers/generated/token_transfer_proxy.ts +++ /dev/null @@ -1,285 +0,0 @@ -/** - * This file is auto-generated using abi-gen. Don't edit directly. - * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. - */ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; -import * as Web3 from 'web3'; - -import {TxData, TxDataPayable} from '../../types'; -import {classUtils} from '../../utils/class_utils'; - -import {BaseContract} from './base_contract'; - -export class TokenTransferProxyContract extends BaseContract { - public transferFrom = { - async sendTransactionAsync( - token: string, - from: string, - to: string, - value: BigNumber, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transferFrom.estimateGasAsync.bind( - self, - token, - from, - to, - value, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transferFrom, self.web3ContractInstance, - )( - token, - from, - to, - value, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - token: string, - from: string, - to: string, - value: BigNumber, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transferFrom.estimateGas, self.web3ContractInstance, - )( - token, - from, - to, - value, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - token: string, - from: string, - to: string, - value: BigNumber, - txData: TxData = {}, - ): string { - const self = this as TokenTransferProxyContract; - const abiEncodedTransactionData = self.web3ContractInstance.transferFrom.getData(); - return abiEncodedTransactionData; - }, - }; - public addAuthorizedAddress = { - async sendTransactionAsync( - target: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.addAuthorizedAddress.estimateGasAsync.bind( - self, - target, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.addAuthorizedAddress, self.web3ContractInstance, - )( - target, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - target: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.addAuthorizedAddress.estimateGas, self.web3ContractInstance, - )( - target, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - target: string, - txData: TxData = {}, - ): string { - const self = this as TokenTransferProxyContract; - const abiEncodedTransactionData = self.web3ContractInstance.addAuthorizedAddress.getData(); - return abiEncodedTransactionData; - }, - }; - public authorities = { - async callAsync( - index: BigNumber, - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as TokenTransferProxyContract; - const result = await promisify<string - >( - self.web3ContractInstance.authorities.call, - self.web3ContractInstance, - )( - index, - ); - return result; - }, - }; - public removeAuthorizedAddress = { - async sendTransactionAsync( - target: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.removeAuthorizedAddress.estimateGasAsync.bind( - self, - target, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.removeAuthorizedAddress, self.web3ContractInstance, - )( - target, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - target: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.removeAuthorizedAddress.estimateGas, self.web3ContractInstance, - )( - target, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - target: string, - txData: TxData = {}, - ): string { - const self = this as TokenTransferProxyContract; - const abiEncodedTransactionData = self.web3ContractInstance.removeAuthorizedAddress.getData(); - return abiEncodedTransactionData; - }, - }; - public owner = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string - > { - const self = this as TokenTransferProxyContract; - const result = await promisify<string - >( - self.web3ContractInstance.owner.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public authorized = { - async callAsync( - index: string, - defaultBlock?: Web3.BlockParam, - ): Promise<boolean - > { - const self = this as TokenTransferProxyContract; - const result = await promisify<boolean - >( - self.web3ContractInstance.authorized.call, - self.web3ContractInstance, - )( - index, - ); - return result; - }, - }; - public getAuthorizedAddresses = { - async callAsync( - defaultBlock?: Web3.BlockParam, - ): Promise<string[] - > { - const self = this as TokenTransferProxyContract; - const result = await promisify<string[] - >( - self.web3ContractInstance.getAuthorizedAddresses.call, - self.web3ContractInstance, - )( - ); - return result; - }, - }; - public transferOwnership = { - async sendTransactionAsync( - newOwner: string, - txData: TxData = {}, - ): Promise<string> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - self.transferOwnership.estimateGasAsync.bind( - self, - newOwner, - ), - ); - const txHash = await promisify<string>( - self.web3ContractInstance.transferOwnership, self.web3ContractInstance, - )( - newOwner, - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - newOwner: string, - txData: TxData = {}, - ): Promise<number> { - const self = this as TokenTransferProxyContract; - const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self.web3ContractInstance.transferOwnership.estimateGas, self.web3ContractInstance, - )( - newOwner, - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - newOwner: string, - txData: TxData = {}, - ): string { - const self = this as TokenTransferProxyContract; - const abiEncodedTransactionData = self.web3ContractInstance.transferOwnership.getData(); - return abiEncodedTransactionData; - }, - }; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { - super(web3ContractInstance, defaults); - classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); - } -} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts index 064b826d8..f54aaf0f8 100644 --- a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts @@ -1,13 +1,13 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import {artifacts} from '../artifacts'; -import {Token, TokenMetadata, ZeroExError} from '../types'; -import {assert} from '../utils/assert'; -import {constants} from '../utils/constants'; +import { artifacts } from '../artifacts'; +import { Token, TokenMetadata } from '../types'; +import { assert } from '../utils/assert'; +import { constants } from '../utils/constants'; -import {ContractWrapper} from './contract_wrapper'; -import {TokenRegistryContract} from './generated/token_registry'; +import { ContractWrapper } from './contract_wrapper'; +import { TokenRegistryContract } from './generated/token_registry'; /** * This class includes all the functionality related to interacting with the 0x Token Registry smart contract. @@ -15,7 +15,7 @@ import {TokenRegistryContract} from './generated/token_registry'; export class TokenRegistryWrapper extends ContractWrapper { private _tokenRegistryContractIfExists?: TokenRegistryContract; private _contractAddressIfExists?: string; - private static _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined { + private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined { if (metadata[0] === constants.NULL_ADDRESS) { return undefined; } @@ -36,12 +36,9 @@ export class TokenRegistryWrapper extends ContractWrapper { * @return An array of objects that conform to the Token interface. */ public async getTokensAsync(): Promise<Token[]> { - const tokenRegistryContract = await this._getTokenRegistryContractAsync(); - const addresses = await this.getTokenAddressesAsync(); - const tokenPromises: Array<Promise<Token|undefined>> = _.map( - addresses, - async (address: string) => this.getTokenIfExistsAsync(address), + const tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) => + this.getTokenIfExistsAsync(address), ); const tokens = await Promise.all(tokenPromises); return tokens as Token[]; @@ -59,7 +56,7 @@ export class TokenRegistryWrapper extends ContractWrapper { * Retrieves a token by address currently listed in the Token Registry smart contract * @return An object that conforms to the Token interface or undefined if token not found. */ - public async getTokenIfExistsAsync(address: string): Promise<Token|undefined> { + public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> { assert.isETHAddressHex('address', address); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); @@ -67,7 +64,7 @@ export class TokenRegistryWrapper extends ContractWrapper { const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); return token; } - public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string|undefined> { + public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string | undefined> { assert.isString('symbol', symbol); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol); @@ -76,7 +73,7 @@ export class TokenRegistryWrapper extends ContractWrapper { } return addressIfExists; } - public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string|undefined> { + public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string | undefined> { assert.isString('name', name); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name); @@ -85,14 +82,14 @@ export class TokenRegistryWrapper extends ContractWrapper { } return addressIfExists; } - public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token|undefined> { + public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token | undefined> { assert.isString('symbol', symbol); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol); const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); return token; } - public async getTokenByNameIfExistsAsync(name: string): Promise<Token|undefined> { + public async getTokenByNameIfExistsAsync(name: string): Promise<Token | undefined> { assert.isString('name', name); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenByName.callAsync(name); @@ -106,7 +103,8 @@ export class TokenRegistryWrapper extends ContractWrapper { */ public getContractAddress(): string { const contractAddress = this._getContractAddress( - artifacts.TokenRegistryArtifact, this._contractAddressIfExists, + artifacts.TokenRegistryArtifact, + this._contractAddressIfExists, ); return contractAddress; } @@ -118,10 +116,12 @@ export class TokenRegistryWrapper extends ContractWrapper { return this._tokenRegistryContractIfExists; } const web3ContractInstance = await this._instantiateContractIfExistsAsync( - artifacts.TokenRegistryArtifact, this._contractAddressIfExists, + artifacts.TokenRegistryArtifact, + this._contractAddressIfExists, ); const contractInstance = new TokenRegistryContract( - web3ContractInstance, this._web3Wrapper.getContractDefaults(), + web3ContractInstance, + this._web3Wrapper.getContractDefaults(), ); this._tokenRegistryContractIfExists = contractInstance; return this._tokenRegistryContractIfExists; diff --git a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts index 1a16e3540..f5d9d108a 100644 --- a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts @@ -1,11 +1,10 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import {artifacts} from '../artifacts'; -import {ZeroExError} from '../types'; +import { artifacts } from '../artifacts'; -import {ContractWrapper} from './contract_wrapper'; -import {TokenTransferProxyContract} from './generated/token_transfer_proxy'; +import { ContractWrapper } from './contract_wrapper'; +import { TokenTransferProxyContract } from './generated/token_transfer_proxy'; /** * This class includes the functionality related to interacting with the TokenTransferProxy contract. @@ -43,7 +42,8 @@ export class TokenTransferProxyWrapper extends ContractWrapper { */ public getContractAddress(): string { const contractAddress = this._getContractAddress( - artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists, + artifacts.TokenTransferProxyArtifact, + this._contractAddressIfExists, ); return contractAddress; } @@ -55,10 +55,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper { return this._tokenTransferProxyContractIfExists; } const web3ContractInstance = await this._instantiateContractIfExistsAsync( - artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists, + artifacts.TokenTransferProxyArtifact, + this._contractAddressIfExists, ); const contractInstance = new TokenTransferProxyContract( - web3ContractInstance, this._web3Wrapper.getContractDefaults(), + web3ContractInstance, + this._web3Wrapper.getContractDefaults(), ); this._tokenTransferProxyContractIfExists = contractInstance; return this._tokenTransferProxyContractIfExists; diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts index 684f291a5..7943f4a60 100644 --- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_wrapper.ts @@ -1,29 +1,27 @@ -import {schemas} from '@0xproject/json-schemas'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { schemas } from '@0xproject/json-schemas'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import {artifacts} from '../artifacts'; +import { artifacts } from '../artifacts'; import { + BlockRange, EventCallback, IndexedFilterValues, LogWithDecodedArgs, MethodOpts, - SubscriptionOpts, TokenContractEventArgs, TokenEvents, TransactionOpts, ZeroExError, } from '../types'; -import {AbiDecoder} from '../utils/abi_decoder'; -import {assert} from '../utils/assert'; -import {constants} from '../utils/constants'; +import { AbiDecoder } from '../utils/abi_decoder'; +import { assert } from '../utils/assert'; +import { constants } from '../utils/constants'; -import {ContractWrapper} from './contract_wrapper'; -import {TokenContract} from './generated/token'; -import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper'; - -const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47275; +import { ContractWrapper } from './contract_wrapper'; +import { TokenContract } from './generated/token'; +import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper'; /** * This class includes all the functionality related to interacting with ERC20 token contracts. @@ -32,10 +30,14 @@ const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47275; */ export class TokenWrapper extends ContractWrapper { public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - private _tokenContractsByAddress: {[address: string]: TokenContract}; + private _tokenContractsByAddress: { [address: string]: TokenContract }; private _tokenTransferProxyWrapper: TokenTransferProxyWrapper; - constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, - tokenTransferProxyWrapper: TokenTransferProxyWrapper) { + constructor( + web3Wrapper: Web3Wrapper, + networkId: number, + abiDecoder: AbiDecoder, + tokenTransferProxyWrapper: TokenTransferProxyWrapper, + ) { super(web3Wrapper, networkId, abiDecoder); this._tokenContractsByAddress = {}; this._tokenTransferProxyWrapper = tokenTransferProxyWrapper; @@ -47,8 +49,11 @@ export class TokenWrapper extends ContractWrapper { * @param methodOpts Optional arguments this method accepts. * @return The owner's ERC20 token balance in base units. */ - public async getBalanceAsync(tokenAddress: string, ownerAddress: string, - methodOpts?: MethodOpts): Promise<BigNumber> { + public async getBalanceAsync( + tokenAddress: string, + ownerAddress: string, + methodOpts?: MethodOpts, + ): Promise<BigNumber> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); @@ -70,8 +75,13 @@ export class TokenWrapper extends ContractWrapper { * @param txOpts Transaction parameters. * @return Transaction hash. */ - public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string, - amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { + public async setAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + spenderAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise<string> { await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); assert.isETHAddressHex('spenderAddress', spenderAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); @@ -97,10 +107,18 @@ export class TokenWrapper extends ContractWrapper { * @param txOpts Transaction parameters. * @return Transaction hash. */ - public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string, - spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> { + public async setUnlimitedAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + spenderAddress: string, + txOpts: TransactionOpts = {}, + ): Promise<string> { const txHash = await this.setAllowanceAsync( - tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, + tokenAddress, + ownerAddress, + spenderAddress, + this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + txOpts, ); return txHash; } @@ -112,8 +130,12 @@ export class TokenWrapper extends ContractWrapper { * @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching. * @param methodOpts Optional arguments this method accepts. */ - public async getAllowanceAsync(tokenAddress: string, ownerAddress: string, - spenderAddress: string, methodOpts?: MethodOpts): Promise<BigNumber> { + public async getAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + spenderAddress: string, + methodOpts?: MethodOpts, + ): Promise<BigNumber> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); @@ -130,8 +152,11 @@ export class TokenWrapper extends ContractWrapper { * @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving. * @param methodOpts Optional arguments this method accepts. */ - public async getProxyAllowanceAsync(tokenAddress: string, ownerAddress: string, - methodOpts?: MethodOpts): Promise<BigNumber> { + public async getProxyAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + methodOpts?: MethodOpts, + ): Promise<BigNumber> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); @@ -149,15 +174,23 @@ export class TokenWrapper extends ContractWrapper { * @param txOpts Transaction parameters. * @return Transaction hash. */ - public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string, - amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { + public async setProxyAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise<string> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); const txHash = await this.setAllowanceAsync( - tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts, + tokenAddress, + ownerAddress, + proxyAddress, + amountInBaseUnits, + txOpts, ); return txHash; } @@ -173,10 +206,15 @@ export class TokenWrapper extends ContractWrapper { * @return Transaction hash. */ public async setUnlimitedProxyAllowanceAsync( - tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {}, + tokenAddress: string, + ownerAddress: string, + txOpts: TransactionOpts = {}, ): Promise<string> { const txHash = await this.setProxyAllowanceAsync( - tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, + tokenAddress, + ownerAddress, + this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + txOpts, ); return txHash; } @@ -189,8 +227,13 @@ export class TokenWrapper extends ContractWrapper { * @param txOpts Transaction parameters. * @return Transaction hash. */ - public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string, - amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { + public async transferAsync( + tokenAddress: string, + fromAddress: string, + toAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise<string> { assert.isETHAddressHex('tokenAddress', tokenAddress); await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); assert.isETHAddressHex('toAddress', toAddress); @@ -224,9 +267,14 @@ export class TokenWrapper extends ContractWrapper { * @param txOpts Transaction parameters. * @return Transaction hash. */ - public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string, - senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): - Promise<string> { + public async transferFromAsync( + tokenAddress: string, + fromAddress: string, + toAddress: string, + senderAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise<string> { assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('fromAddress', fromAddress); assert.isETHAddressHex('toAddress', toAddress); @@ -246,7 +294,9 @@ export class TokenWrapper extends ContractWrapper { } const txHash = await tokenContract.transferFrom.sendTransactionAsync( - fromAddress, toAddress, amountInBaseUnits, + fromAddress, + toAddress, + amountInBaseUnits, { from: senderAddress, gas: txOpts.gasLimit, @@ -265,14 +315,21 @@ export class TokenWrapper extends ContractWrapper { * @return Subscription token used later to unsubscribe */ public subscribe<ArgsType extends TokenContractEventArgs>( - tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues, - callback: EventCallback<ArgsType>): string { + tokenAddress: string, + eventName: TokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback<ArgsType>, + ): string { assert.isETHAddressHex('tokenAddress', tokenAddress); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.isFunction('callback', callback); const subscriptionToken = this._subscribe<ArgsType>( - tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback, + tokenAddress, + eventName, + indexFilterValues, + artifacts.TokenArtifact.abi, + callback, ); return subscriptionToken; } @@ -284,23 +341,36 @@ export class TokenWrapper extends ContractWrapper { this._unsubscribe(subscriptionToken); } /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super.unsubscribeAll(); + } + /** * Gets historical logs without creating a subscription * @param tokenAddress An address of the token that emmited the logs. * @param eventName The token contract event you would like to subscribe to. - * @param subscriptionOpts Subscriptions options that let you configure the subscription. + * @param blockRange Block range to get logs from. * @param indexFilterValues An object where the keys are indexed args returned by the event and * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` * @return Array of logs that match the parameters */ public async getLogsAsync<ArgsType extends TokenContractEventArgs>( - tokenAddress: string, eventName: TokenEvents, subscriptionOpts: SubscriptionOpts, - indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> { + tokenAddress: string, + eventName: TokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise<Array<LogWithDecodedArgs<ArgsType>>> { assert.isETHAddressHex('tokenAddress', tokenAddress); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); - assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); const logs = await this._getLogsAsync<ArgsType>( - tokenAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.TokenArtifact.abi, + tokenAddress, + eventName, + blockRange, + indexFilterValues, + artifacts.TokenArtifact.abi, ); return logs; } @@ -314,11 +384,10 @@ export class TokenWrapper extends ContractWrapper { return tokenContract; } const web3ContractInstance = await this._instantiateContractIfExistsAsync( - artifacts.TokenArtifact, tokenAddress, - ); - const contractInstance = new TokenContract( - web3ContractInstance, this._web3Wrapper.getContractDefaults(), + artifacts.TokenArtifact, + tokenAddress, ); + const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); tokenContract = contractInstance; this._tokenContractsByAddress[tokenAddress] = tokenContract; return tokenContract; diff --git a/packages/0x.js/src/globals.d.ts b/packages/0x.js/src/globals.d.ts index 4fa1cfd9c..4f4932b6e 100644 --- a/packages/0x.js/src/globals.d.ts +++ b/packages/0x.js/src/globals.d.ts @@ -1,5 +1,3 @@ -/// <reference types='chai-typescript-typings' /> -/// <reference types='chai-as-promised-typescript-typings' /> declare module 'web3_beta'; declare module 'chai-bignumber'; declare module 'dirty-chai'; @@ -27,18 +25,6 @@ declare module '*.json' { /* tslint:enable */ } -// find-version declarations -declare function findVersions(version: string): string[]; -declare module 'find-versions' { - export = findVersions; -} - -// compare-version declarations -declare function compareVersions(firstVersion: string, secondVersion: string): number; -declare module 'compare-versions' { - export = compareVersions; -} - declare module 'ethereumjs-abi' { const soliditySHA3: (argTypes: string[], args: any[]) => Buffer; } @@ -57,8 +43,7 @@ declare module 'truffle-hdwallet-provider' { } // abi-decoder declarations -interface DecodedLogArg { -} +interface DecodedLogArg {} interface DecodedLog { name: string; events: DecodedLogArg[]; diff --git a/packages/0x.js/src/globalsAugment.d.ts b/packages/0x.js/src/globalsAugment.d.ts index 60e2312a3..3e2f2216b 100644 --- a/packages/0x.js/src/globalsAugment.d.ts +++ b/packages/0x.js/src/globalsAugment.d.ts @@ -1,4 +1,4 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; // HACK: This module overrides the Chai namespace so that we can use BigNumber types inside. // Source: https://github.com/Microsoft/TypeScript/issues/7352#issuecomment-191547232 @@ -9,7 +9,7 @@ declare global { /* tslint:disable */ namespace Chai { interface NumberComparer { - (value: number|BigNumber, message?: string): Assertion; + (value: number | BigNumber, message?: string): Assertion; } interface NumericComparison { greaterThan: NumberComparer; @@ -18,6 +18,6 @@ declare global { /* tslint:enable */ interface DecodedLogArg { name: string; - value: string|BigNumber; + value: string | BigNumber; } } diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index d4193a3e9..599c3a2b0 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -1,7 +1,8 @@ -export {ZeroEx} from './0x'; +export { ZeroEx } from './0x'; export { Order, + BlockParamLiteral, SignedOrder, ECSignature, ZeroExError, @@ -12,7 +13,7 @@ export { ExchangeEvents, TokenEvents, IndexedFilterValues, - SubscriptionOpts, + BlockRange, BlockParam, OrderCancellationRequest, OrderFillRequest, @@ -23,11 +24,14 @@ export { TransferContractEventArgs, ApprovalContractEventArgs, TokenContractEventArgs, + EtherTokenContractEventArgs, + WithdrawalContractEventArgs, + DepositContractEventArgs, ContractEventArgs, ContractEventArg, Web3Provider, ZeroExConfig, - TransactionReceipt, + EtherTokenEvents, TransactionReceiptWithDecodedLogs, LogWithDecodedArgs, MethodOpts, @@ -42,3 +46,5 @@ export { OrderStateInvalid, OrderState, } from './types'; + +export { TransactionReceipt } from '@0xproject/types'; diff --git a/packages/0x.js/src/order_watcher/event_watcher.ts b/packages/0x.js/src/order_watcher/event_watcher.ts index d5b30d567..5d05bfb60 100644 --- a/packages/0x.js/src/order_watcher/event_watcher.ts +++ b/packages/0x.js/src/order_watcher/event_watcher.ts @@ -1,17 +1,10 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; +import { intervalUtils } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import { - BlockParamLiteral, - EventCallback, - EventWatcherCallback, - ZeroExError, -} from '../types'; -import {AbiDecoder} from '../utils/abi_decoder'; -import {assert} from '../utils/assert'; -import {intervalUtils} from '../utils/interval_utils'; -import {utils} from '../utils/utils'; +import { BlockParamLiteral, EventWatcherCallback, ZeroExError } from '../types'; +import { assert } from '../utils/assert'; const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200; @@ -29,11 +22,11 @@ export class EventWatcher { private _pollingIntervalMs: number; private _intervalIdIfExists?: NodeJS.Timer; private _lastEvents: Web3.LogEntry[] = []; - constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined|number) { + constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined | number) { this._web3Wrapper = web3Wrapper; - this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ? - DEFAULT_EVENT_POLLING_INTERVAL_MS : - pollingIntervalIfExistsMs; + this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) + ? DEFAULT_EVENT_POLLING_INTERVAL_MS + : pollingIntervalIfExistsMs; } public subscribe(callback: EventWatcherCallback): void { assert.isFunction('callback', callback); @@ -41,7 +34,12 @@ export class EventWatcher { throw new Error(ZeroExError.SubscriptionAlreadyPresent); } this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval( - this._pollForBlockchainEventsAsync.bind(this, callback), this._pollingIntervalMs, + this._pollForBlockchainEventsAsync.bind(this, callback), + this._pollingIntervalMs, + (err: Error) => { + this.unsubscribe(); + callback(err); + }, ); } public unsubscribe(): void { @@ -53,6 +51,10 @@ export class EventWatcher { } private async _pollForBlockchainEventsAsync(callback: EventWatcherCallback): Promise<void> { const pendingEvents = await this._getEventsAsync(); + if (_.isUndefined(pendingEvents)) { + // HACK: This should never happen, but happens frequently on CI due to a ganache bug + return; + } if (pendingEvents.length === 0) { // HACK: Sometimes when node rebuilds the pending block we get back the empty result. // We don't want to emit a lot of removal events and bring them back after a couple of miliseconds, @@ -74,7 +76,9 @@ export class EventWatcher { return events; } private async _emitDifferencesAsync( - logs: Web3.LogEntry[], logEventState: LogEventState, callback: EventWatcherCallback, + logs: Web3.LogEntry[], + logEventState: LogEventState, + callback: EventWatcherCallback, ): Promise<void> { for (const log of logs) { const logEvent = { @@ -82,7 +86,7 @@ export class EventWatcher { ...log, }; if (!_.isUndefined(this._intervalIdIfExists)) { - callback(logEvent); + callback(null, logEvent); } } } diff --git a/packages/0x.js/src/order_watcher/expiration_watcher.ts b/packages/0x.js/src/order_watcher/expiration_watcher.ts index 9a1bb1ca4..00b62162d 100644 --- a/packages/0x.js/src/order_watcher/expiration_watcher.ts +++ b/packages/0x.js/src/order_watcher/expiration_watcher.ts @@ -1,11 +1,9 @@ -import {BigNumber} from 'bignumber.js'; -import {RBTree} from 'bintrees'; +import { BigNumber, intervalUtils } from '@0xproject/utils'; +import { RBTree } from 'bintrees'; import * as _ from 'lodash'; -import {ZeroEx} from '../0x'; -import {SignedOrder, ZeroExError} from '../types'; -import {intervalUtils} from '../utils/interval_utils'; -import {utils} from '../utils/utils'; +import { ZeroExError } from '../types'; +import { utils } from '../utils/utils'; const DEFAULT_EXPIRATION_MARGIN_MS = 0; const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50; @@ -15,62 +13,62 @@ const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50; * It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs` */ export class ExpirationWatcher { - private orderHashByExpirationRBTree: RBTree<string>; - private expiration: {[orderHash: string]: BigNumber} = {}; - private orderExpirationCheckingIntervalMs: number; - private expirationMarginMs: number; - private orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer; - constructor(expirationMarginIfExistsMs?: number, - orderExpirationCheckingIntervalIfExistsMs?: number) { - this.expirationMarginMs = expirationMarginIfExistsMs || - DEFAULT_EXPIRATION_MARGIN_MS; - this.orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs || - DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS; - const scoreFunction = (orderHash: string) => this.expiration[orderHash].toNumber(); + private _orderHashByExpirationRBTree: RBTree<string>; + private _expiration: { [orderHash: string]: BigNumber } = {}; + private _orderExpirationCheckingIntervalMs: number; + private _expirationMarginMs: number; + private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer; + constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) { + this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS; + this._orderExpirationCheckingIntervalMs = + expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS; + const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber(); const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs); - this.orderHashByExpirationRBTree = new RBTree(comparator); + this._orderHashByExpirationRBTree = new RBTree(comparator); } public subscribe(callback: (orderHash: string) => void): void { - if (!_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) { + if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) { throw new Error(ZeroExError.SubscriptionAlreadyPresent); } - this.orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( - this.pruneExpiredOrders.bind(this, callback), this.orderExpirationCheckingIntervalMs, + this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setInterval( + this._pruneExpiredOrders.bind(this, callback), + this._orderExpirationCheckingIntervalMs, + _.noop, // _pruneExpiredOrders never throws ); } public unsubscribe(): void { - if (_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) { + if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) { throw new Error(ZeroExError.SubscriptionNotFound); } - intervalUtils.clearAsyncExcludingInterval(this.orderExpirationCheckingIntervalIdIfExists); - delete this.orderExpirationCheckingIntervalIdIfExists; + intervalUtils.clearInterval(this._orderExpirationCheckingIntervalIdIfExists); + delete this._orderExpirationCheckingIntervalIdIfExists; } public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void { - this.expiration[orderHash] = expirationUnixTimestampMs; - this.orderHashByExpirationRBTree.insert(orderHash); + this._expiration[orderHash] = expirationUnixTimestampMs; + this._orderHashByExpirationRBTree.insert(orderHash); } public removeOrder(orderHash: string): void { - this.orderHashByExpirationRBTree.remove(orderHash); - delete this.expiration[orderHash]; + this._orderHashByExpirationRBTree.remove(orderHash); + delete this._expiration[orderHash]; } - private pruneExpiredOrders(callback: (orderHash: string) => void): void { + private _pruneExpiredOrders(callback: (orderHash: string) => void): void { const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs(); while (true) { - const hasTrakedOrders = this.orderHashByExpirationRBTree.size === 0; + const hasTrakedOrders = this._orderHashByExpirationRBTree.size === 0; if (hasTrakedOrders) { break; } - const nextOrderHashToExpire = this.orderHashByExpirationRBTree.min(); - const hasNoExpiredOrders = this.expiration[nextOrderHashToExpire].greaterThan( - currentUnixTimestampMs.plus(this.expirationMarginMs), + const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min(); + const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].greaterThan( + currentUnixTimestampMs.plus(this._expirationMarginMs), ); - const isSubscriptionActive = _.isUndefined(this.orderExpirationCheckingIntervalIdIfExists); + const isSubscriptionActive = _.isUndefined(this._orderExpirationCheckingIntervalIdIfExists); if (hasNoExpiredOrders || isSubscriptionActive) { break; } - const orderHash = this.orderHashByExpirationRBTree.min(); - this.orderHashByExpirationRBTree.remove(orderHash); - delete this.expiration[orderHash]; + const orderHash = this._orderHashByExpirationRBTree.min(); + this._orderHashByExpirationRBTree.remove(orderHash); + delete this._expiration[orderHash]; callback(orderHash); } } diff --git a/packages/0x.js/src/order_watcher/order_state_watcher.ts b/packages/0x.js/src/order_watcher/order_state_watcher.ts index 08f52d6e1..12ac60960 100644 --- a/packages/0x.js/src/order_watcher/order_state_watcher.ts +++ b/packages/0x.js/src/order_watcher/order_state_watcher.ts @@ -1,17 +1,19 @@ -import {schemas} from '@0xproject/json-schemas'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; +import { schemas } from '@0xproject/json-schemas'; +import { intervalUtils } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import {ZeroEx} from '../0x'; -import {artifacts} from '../artifacts'; -import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; -import {TokenWrapper} from '../contract_wrappers/token_wrapper'; -import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; -import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store'; +import { ZeroEx } from '../0x'; +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { TokenWrapper } from '../contract_wrappers/token_wrapper'; +import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; +import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store'; import { ApprovalContractEventArgs, BlockParamLiteral, ContractEventArgs, + DepositContractEventArgs, + EtherTokenEvents, ExchangeContractErrs, ExchangeEvents, LogCancelContractEventArgs, @@ -24,17 +26,16 @@ import { SignedOrder, TokenEvents, TransferContractEventArgs, - Web3Provider, + WithdrawalContractEventArgs, ZeroExError, } from '../types'; -import {AbiDecoder} from '../utils/abi_decoder'; -import {assert} from '../utils/assert'; -import {intervalUtils} from '../utils/interval_utils'; -import {OrderStateUtils} from '../utils/order_state_utils'; -import {utils} from '../utils/utils'; +import { AbiDecoder } from '../utils/abi_decoder'; +import { assert } from '../utils/assert'; +import { OrderStateUtils } from '../utils/order_state_utils'; +import { utils } from '../utils/utils'; -import {EventWatcher} from './event_watcher'; -import {ExpirationWatcher} from './expiration_watcher'; +import { EventWatcher } from './event_watcher'; +import { ExpirationWatcher } from './expiration_watcher'; interface DependentOrderHashes { [makerAddress: string]: { @@ -73,7 +74,10 @@ export class OrderStateWatcher { private _cleanupJobInterval: number; private _cleanupJobIntervalIdIfExists?: NodeJS.Timer; constructor( - web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper, + web3Wrapper: Web3Wrapper, + abiDecoder: AbiDecoder, + token: TokenWrapper, + exchange: ExchangeWrapper, config?: OrderStateWatcherConfig, ) { this._abiDecoder = abiDecoder; @@ -81,24 +85,26 @@ export class OrderStateWatcher { const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs; this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs); this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( - token, BlockParamLiteral.Pending, + token, + BlockParamLiteral.Pending, ); this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange); this._orderStateUtils = new OrderStateUtils( - this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore, + this._balanceAndProxyAllowanceLazyStore, + this._orderFilledCancelledLazyStore, ); - const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) ? - undefined : - config.orderExpirationCheckingIntervalMs; - const expirationMarginIfExistsMs = _.isUndefined(config) ? - undefined : - config.expirationMarginMs; + const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) + ? undefined + : config.orderExpirationCheckingIntervalMs; + const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs; this._expirationWatcher = new ExpirationWatcher( - expirationMarginIfExistsMs, orderExpirationCheckingIntervalMsIfExists, + expirationMarginIfExistsMs, + orderExpirationCheckingIntervalMsIfExists, ); - this._cleanupJobInterval = _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs) ? - DEFAULT_CLEANUP_JOB_INTERVAL_MS : - config.cleanupJobIntervalMs; + this._cleanupJobInterval = + _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs) + ? DEFAULT_CLEANUP_JOB_INTERVAL_MS + : config.cleanupJobIntervalMs; } /** * Add an order to the orderStateWatcher. Before the order is added, it's @@ -110,7 +116,7 @@ export class OrderStateWatcher { const orderHash = ZeroEx.getOrderHashHex(signedOrder); assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker); this._orderByOrderHash[orderHash] = signedOrder; - this.addToDependentOrderHashes(signedOrder, orderHash); + this._addToDependentOrderHashes(signedOrder, orderHash); const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000); this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs); } @@ -126,10 +132,10 @@ export class OrderStateWatcher { } delete this._orderByOrderHash[orderHash]; delete this._orderStateByOrderHashCache[orderHash]; - const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper; + const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper; const zrxTokenAddress = exchange.getZRXTokenAddress(); - this.removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash); - this.removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash); + this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash); + this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash); this._expirationWatcher.removeOrder(orderHash); } /** @@ -147,7 +153,12 @@ export class OrderStateWatcher { this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this)); this._expirationWatcher.subscribe(this._onOrderExpired.bind(this)); this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( - this._cleanupAsync.bind(this), this._cleanupJobInterval, + this._cleanupAsync.bind(this), + this._cleanupJobInterval, + (err: Error) => { + this.unsubscribe(); + callback(err); + }, ); } /** @@ -200,11 +211,19 @@ export class OrderStateWatcher { if (!_.isUndefined(this._orderByOrderHash[orderHash])) { this.removeOrder(orderHash); if (!_.isUndefined(this._callbackIfExists)) { - this._callbackIfExists(orderState); + this._callbackIfExists(null, orderState); } } } - private async _onEventWatcherCallbackAsync(log: LogEvent): Promise<void> { + private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEvent): Promise<void> { + if (!_.isNull(err)) { + if (!_.isUndefined(this._callbackIfExists)) { + this._callbackIfExists(err); + this.unsubscribe(); + } + return; + } + const log = logIfExists as LogEvent; // At this moment we are sure that no error occured and log is defined. const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log); const isLogDecoded = !_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event); if (!isLogDecoded) { @@ -214,23 +233,23 @@ export class OrderStateWatcher { let makerToken: string; let makerAddress: string; switch (decodedLog.event) { - case TokenEvents.Approval: - { + case TokenEvents.Approval: { // Invalidate cache const args = decodedLog.args as ApprovalContractEventArgs; this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner); // Revalidate orders makerToken = decodedLog.address; makerAddress = args._owner; - if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && - !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { + if ( + !_.isUndefined(this._dependentOrderHashes[makerAddress]) && + !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken]) + ) { const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); await this._emitRevalidateOrdersAsync(orderHashes); } break; } - case TokenEvents.Transfer: - { + case TokenEvents.Transfer: { // Invalidate cache const args = decodedLog.args as TransferContractEventArgs; this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from); @@ -238,15 +257,48 @@ export class OrderStateWatcher { // Revalidate orders makerToken = decodedLog.address; makerAddress = args._from; - if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && - !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { + if ( + !_.isUndefined(this._dependentOrderHashes[makerAddress]) && + !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken]) + ) { + const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); + await this._emitRevalidateOrdersAsync(orderHashes); + } + break; + } + case EtherTokenEvents.Deposit: { + // Invalidate cache + const args = decodedLog.args as DepositContractEventArgs; + this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner); + // Revalidate orders + makerToken = decodedLog.address; + makerAddress = args._owner; + if ( + !_.isUndefined(this._dependentOrderHashes[makerAddress]) && + !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken]) + ) { + const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); + await this._emitRevalidateOrdersAsync(orderHashes); + } + break; + } + case EtherTokenEvents.Withdrawal: { + // Invalidate cache + const args = decodedLog.args as WithdrawalContractEventArgs; + this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner); + // Revalidate orders + makerToken = decodedLog.address; + makerAddress = args._owner; + if ( + !_.isUndefined(this._dependentOrderHashes[makerAddress]) && + !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken]) + ) { const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); await this._emitRevalidateOrdersAsync(orderHashes); } break; } - case ExchangeEvents.LogFill: - { + case ExchangeEvents.LogFill: { // Invalidate cache const args = decodedLog.args as LogFillContractEventArgs; this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash); @@ -258,8 +310,7 @@ export class OrderStateWatcher { } break; } - case ExchangeEvents.LogCancel: - { + case ExchangeEvents.LogCancel: { // Invalidate cache const args = decodedLog.args as LogCancelContractEventArgs; this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash); @@ -293,10 +344,10 @@ export class OrderStateWatcher { } else { this._orderStateByOrderHashCache[orderHash] = orderState; } - this._callbackIfExists(orderState); + this._callbackIfExists(null, orderState); } } - private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void { + private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void { if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) { this._dependentOrderHashes[signedOrder.maker] = {}; } @@ -310,7 +361,7 @@ export class OrderStateWatcher { } this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash); } - private removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) { + private _removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) { this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash); if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) { delete this._dependentOrderHashes[makerAddress][tokenAddress]; @@ -320,7 +371,7 @@ export class OrderStateWatcher { } } private _getZRXTokenAddress(): string { - const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper; + const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper; const zrxTokenAddress = exchange.getZRXTokenAddress(); return zrxTokenAddress; } diff --git a/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts b/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts index e8601e678..20b09d606 100644 --- a/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts +++ b/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts @@ -1,87 +1,96 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; -import {SignedOrder} from '../types'; +import { SignedOrder } from '../types'; export class RemainingFillableCalculator { - private signedOrder: SignedOrder; - private isMakerTokenZRX: boolean; + private _signedOrder: SignedOrder; + private _isMakerTokenZRX: boolean; // Transferrable Amount is the minimum of Approval and Balance - private transferrableMakerTokenAmount: BigNumber; - private transferrableMakerFeeTokenAmount: BigNumber; - private remainingMakerTokenAmount: BigNumber; - private remainingMakerFeeAmount: BigNumber; - constructor(signedOrder: SignedOrder, - isMakerTokenZRX: boolean, - transferrableMakerTokenAmount: BigNumber, - transferrableMakerFeeTokenAmount: BigNumber, - remainingMakerTokenAmount: BigNumber) { - this.signedOrder = signedOrder; - this.isMakerTokenZRX = isMakerTokenZRX; - this.transferrableMakerTokenAmount = transferrableMakerTokenAmount; - this.transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount; - this.remainingMakerTokenAmount = remainingMakerTokenAmount; - this.remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee) - .dividedToIntegerBy(signedOrder.makerTokenAmount); + private _transferrableMakerTokenAmount: BigNumber; + private _transferrableMakerFeeTokenAmount: BigNumber; + private _remainingMakerTokenAmount: BigNumber; + private _remainingMakerFeeAmount: BigNumber; + constructor( + signedOrder: SignedOrder, + isMakerTokenZRX: boolean, + transferrableMakerTokenAmount: BigNumber, + transferrableMakerFeeTokenAmount: BigNumber, + remainingMakerTokenAmount: BigNumber, + ) { + this._signedOrder = signedOrder; + this._isMakerTokenZRX = isMakerTokenZRX; + this._transferrableMakerTokenAmount = transferrableMakerTokenAmount; + this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount; + this._remainingMakerTokenAmount = remainingMakerTokenAmount; + this._remainingMakerFeeAmount = remainingMakerTokenAmount + .times(signedOrder.makerFee) + .dividedToIntegerBy(signedOrder.makerTokenAmount); } public computeRemainingMakerFillable(): BigNumber { - if (this.hasSufficientFundsForFeeAndTransferAmount()) { - return this.remainingMakerTokenAmount; + if (this._hasSufficientFundsForFeeAndTransferAmount()) { + return this._remainingMakerTokenAmount; } - if (this.signedOrder.makerFee.isZero()) { - return BigNumber.min(this.remainingMakerTokenAmount, this.transferrableMakerTokenAmount); + if (this._signedOrder.makerFee.isZero()) { + return BigNumber.min(this._remainingMakerTokenAmount, this._transferrableMakerTokenAmount); } - return this.calculatePartiallyFillableMakerTokenAmount(); + return this._calculatePartiallyFillableMakerTokenAmount(); } public computeRemainingTakerFillable(): BigNumber { - return this.computeRemainingMakerFillable().times(this.signedOrder.takerTokenAmount) - .dividedToIntegerBy(this.signedOrder.makerTokenAmount); + return this.computeRemainingMakerFillable() + .times(this._signedOrder.takerTokenAmount) + .dividedToIntegerBy(this._signedOrder.makerTokenAmount); } - private hasSufficientFundsForFeeAndTransferAmount(): boolean { - if (this.isMakerTokenZRX) { - const totalZRXTransferAmountRequired = this.remainingMakerTokenAmount.plus(this.remainingMakerFeeAmount); - const hasSufficientFunds = this.transferrableMakerTokenAmount.greaterThanOrEqualTo( - totalZRXTransferAmountRequired); + private _hasSufficientFundsForFeeAndTransferAmount(): boolean { + if (this._isMakerTokenZRX) { + const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount); + const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo( + totalZRXTransferAmountRequired, + ); return hasSufficientFunds; } else { - const hasSufficientFundsForTransferAmount = this.transferrableMakerTokenAmount.greaterThanOrEqualTo( - this.remainingMakerTokenAmount); - const hasSufficientFundsForFeeAmount = this.transferrableMakerFeeTokenAmount.greaterThanOrEqualTo( - this.remainingMakerFeeAmount); + const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo( + this._remainingMakerTokenAmount, + ); + const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo( + this._remainingMakerFeeAmount, + ); const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount; return hasSufficientFunds; } } - private calculatePartiallyFillableMakerTokenAmount(): BigNumber { + private _calculatePartiallyFillableMakerTokenAmount(): BigNumber { // Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1 - const orderToFeeRatio = this.signedOrder.makerTokenAmount.dividedBy(this.signedOrder.makerFee); + const orderToFeeRatio = this._signedOrder.makerTokenAmount.dividedBy(this._signedOrder.makerFee); // The number of times the maker can fill the order, if each fill only required the transfer of a single // baseUnit of fee tokens. // Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2 - const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this.transferrableMakerFeeTokenAmount, - this.remainingMakerFeeAmount); + const fillableTimesInFeeTokenBaseUnits = BigNumber.min( + this._transferrableMakerFeeTokenAmount, + this._remainingMakerFeeAmount, + ); // The number of times the Maker can fill the order, given the Maker Token Balance // Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time. - let fillableTimesInMakerTokenUnits = this.transferrableMakerTokenAmount.dividedBy(orderToFeeRatio); - if (this.isMakerTokenZRX) { + let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio); + if (this._isMakerTokenZRX) { // If ZRX is the maker token, the Fee and the Maker amount need to be removed from the same pool; // 200 ZRXwei for 2ZRXwei fee can only be filled once (need 202 ZRXwei) - const totalZRXTokenPooled = this.transferrableMakerTokenAmount; + const totalZRXTokenPooled = this._transferrableMakerTokenAmount; // The purchasing power here is less as the tokens are taken from the same Pool // For every one number of fills, we have to take an extra ZRX out of the pool - fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy( - orderToFeeRatio.plus(new BigNumber(1))); - + fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1))); } // When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored. // This can result in a RoundingError being thrown by the Exchange Contract. const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits - .times(this.signedOrder.makerTokenAmount) - .dividedToIntegerBy(this.signedOrder.makerFee); + .times(this._signedOrder.makerTokenAmount) + .dividedToIntegerBy(this._signedOrder.makerFee); const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits - .times(this.signedOrder.makerTokenAmount) - .dividedToIntegerBy(this.signedOrder.makerFee); - const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount, - partiallyFillableFeeTokenAmount); + .times(this._signedOrder.makerTokenAmount) + .dividedToIntegerBy(this._signedOrder.makerFee); + const partiallyFillableAmount = BigNumber.min( + partiallyFillableMakerTokenAmount, + partiallyFillableFeeTokenAmount, + ); return partiallyFillableAmount; } } diff --git a/packages/0x.js/src/schemas/zero_ex_config_schema.ts b/packages/0x.js/src/schemas/zero_ex_config_schema.ts index 121d81257..546b1c2d0 100644 --- a/packages/0x.js/src/schemas/zero_ex_config_schema.ts +++ b/packages/0x.js/src/schemas/zero_ex_config_schema.ts @@ -5,10 +5,9 @@ export const zeroExConfigSchema = { type: 'number', minimum: 0, }, - gasPrice: {$ref: '/Number'}, - exchangeContractAddress: {$ref: '/Address'}, - tokenRegistryContractAddress: {$ref: '/Address'}, - etherTokenContractAddress: {$ref: '/Address'}, + gasPrice: { $ref: '/Number' }, + exchangeContractAddress: { $ref: '/Address' }, + tokenRegistryContractAddress: { $ref: '/Address' }, orderWatcherConfig: { type: 'object', properties: { diff --git a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts index 6225e9e72..33feea105 100644 --- a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts +++ b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts @@ -1,85 +1,86 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import * as Web3 from 'web3'; -import {TokenWrapper} from '../contract_wrappers/token_wrapper'; -import {BlockParamLiteral} from '../types'; +import { TokenWrapper } from '../contract_wrappers/token_wrapper'; +import { BlockParamLiteral } from '../types'; /** * Copy on read store for balances/proxyAllowances of tokens/accounts */ export class BalanceAndProxyAllowanceLazyStore { - private token: TokenWrapper; - private defaultBlock: BlockParamLiteral; - private balance: { + private _token: TokenWrapper; + private _defaultBlock: BlockParamLiteral; + private _balance: { [tokenAddress: string]: { [userAddress: string]: BigNumber; }; }; - private proxyAllowance: { + private _proxyAllowance: { [tokenAddress: string]: { [userAddress: string]: BigNumber; }; }; constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { - this.token = token; - this.defaultBlock = defaultBlock; - this.balance = {}; - this.proxyAllowance = {}; + this._token = token; + this._defaultBlock = defaultBlock; + this._balance = {}; + this._proxyAllowance = {}; } public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> { - if (_.isUndefined(this.balance[tokenAddress]) || _.isUndefined(this.balance[tokenAddress][userAddress])) { + if (_.isUndefined(this._balance[tokenAddress]) || _.isUndefined(this._balance[tokenAddress][userAddress])) { const methodOpts = { - defaultBlock: this.defaultBlock, + defaultBlock: this._defaultBlock, }; - const balance = await this.token.getBalanceAsync(tokenAddress, userAddress, methodOpts); + const balance = await this._token.getBalanceAsync(tokenAddress, userAddress, methodOpts); this.setBalance(tokenAddress, userAddress, balance); } - const cachedBalance = this.balance[tokenAddress][userAddress]; + const cachedBalance = this._balance[tokenAddress][userAddress]; return cachedBalance; } public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void { - if (_.isUndefined(this.balance[tokenAddress])) { - this.balance[tokenAddress] = {}; + if (_.isUndefined(this._balance[tokenAddress])) { + this._balance[tokenAddress] = {}; } - this.balance[tokenAddress][userAddress] = balance; + this._balance[tokenAddress][userAddress] = balance; } public deleteBalance(tokenAddress: string, userAddress: string): void { - if (!_.isUndefined(this.balance[tokenAddress])) { - delete this.balance[tokenAddress][userAddress]; - if (_.isEmpty(this.balance[tokenAddress])) { - delete this.balance[tokenAddress]; + if (!_.isUndefined(this._balance[tokenAddress])) { + delete this._balance[tokenAddress][userAddress]; + if (_.isEmpty(this._balance[tokenAddress])) { + delete this._balance[tokenAddress]; } } } public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> { - if (_.isUndefined(this.proxyAllowance[tokenAddress]) || - _.isUndefined(this.proxyAllowance[tokenAddress][userAddress])) { + if ( + _.isUndefined(this._proxyAllowance[tokenAddress]) || + _.isUndefined(this._proxyAllowance[tokenAddress][userAddress]) + ) { const methodOpts = { - defaultBlock: this.defaultBlock, + defaultBlock: this._defaultBlock, }; - const proxyAllowance = await this.token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts); + const proxyAllowance = await this._token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts); this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance); } - const cachedProxyAllowance = this.proxyAllowance[tokenAddress][userAddress]; + const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress]; return cachedProxyAllowance; } public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void { - if (_.isUndefined(this.proxyAllowance[tokenAddress])) { - this.proxyAllowance[tokenAddress] = {}; + if (_.isUndefined(this._proxyAllowance[tokenAddress])) { + this._proxyAllowance[tokenAddress] = {}; } - this.proxyAllowance[tokenAddress][userAddress] = proxyAllowance; + this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance; } public deleteProxyAllowance(tokenAddress: string, userAddress: string): void { - if (!_.isUndefined(this.proxyAllowance[tokenAddress])) { - delete this.proxyAllowance[tokenAddress][userAddress]; - if (_.isEmpty(this.proxyAllowance[tokenAddress])) { - delete this.proxyAllowance[tokenAddress]; + if (!_.isUndefined(this._proxyAllowance[tokenAddress])) { + delete this._proxyAllowance[tokenAddress][userAddress]; + if (_.isEmpty(this._proxyAllowance[tokenAddress])) { + delete this._proxyAllowance[tokenAddress]; } } } public deleteAll(): void { - this.balance = {}; - this.proxyAllowance = {}; + this._balance = {}; + this._proxyAllowance = {}; } } diff --git a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts index 28b32f9e2..e22364c09 100644 --- a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts +++ b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts @@ -1,62 +1,61 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import * as Web3 from 'web3'; -import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; -import {BlockParamLiteral} from '../types'; +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { BlockParamLiteral } from '../types'; /** * Copy on read store for filled/cancelled taker amounts */ export class OrderFilledCancelledLazyStore { - private exchange: ExchangeWrapper; - private filledTakerAmount: { + private _exchange: ExchangeWrapper; + private _filledTakerAmount: { [orderHash: string]: BigNumber; }; - private cancelledTakerAmount: { + private _cancelledTakerAmount: { [orderHash: string]: BigNumber; }; constructor(exchange: ExchangeWrapper) { - this.exchange = exchange; - this.filledTakerAmount = {}; - this.cancelledTakerAmount = {}; + this._exchange = exchange; + this._filledTakerAmount = {}; + this._cancelledTakerAmount = {}; } public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> { - if (_.isUndefined(this.filledTakerAmount[orderHash])) { + if (_.isUndefined(this._filledTakerAmount[orderHash])) { const methodOpts = { defaultBlock: BlockParamLiteral.Pending, }; - const filledTakerAmount = await this.exchange.getFilledTakerAmountAsync(orderHash, methodOpts); + const filledTakerAmount = await this._exchange.getFilledTakerAmountAsync(orderHash, methodOpts); this.setFilledTakerAmount(orderHash, filledTakerAmount); } - const cachedFilled = this.filledTakerAmount[orderHash]; + const cachedFilled = this._filledTakerAmount[orderHash]; return cachedFilled; } public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void { - this.filledTakerAmount[orderHash] = filledTakerAmount; + this._filledTakerAmount[orderHash] = filledTakerAmount; } public deleteFilledTakerAmount(orderHash: string): void { - delete this.filledTakerAmount[orderHash]; + delete this._filledTakerAmount[orderHash]; } public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> { - if (_.isUndefined(this.cancelledTakerAmount[orderHash])) { + if (_.isUndefined(this._cancelledTakerAmount[orderHash])) { const methodOpts = { defaultBlock: BlockParamLiteral.Pending, }; - const cancelledTakerAmount = await this.exchange.getCancelledTakerAmountAsync(orderHash, methodOpts); + const cancelledTakerAmount = await this._exchange.getCancelledTakerAmountAsync(orderHash, methodOpts); this.setCancelledTakerAmount(orderHash, cancelledTakerAmount); } - const cachedCancelled = this.cancelledTakerAmount[orderHash]; + const cachedCancelled = this._cancelledTakerAmount[orderHash]; return cachedCancelled; } public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void { - this.cancelledTakerAmount[orderHash] = cancelledTakerAmount; + this._cancelledTakerAmount[orderHash] = cancelledTakerAmount; } public deleteCancelledTakerAmount(orderHash: string): void { - delete this.cancelledTakerAmount[orderHash]; + delete this._cancelledTakerAmount[orderHash]; } public deleteAll(): void { - this.filledTakerAmount = {}; - this.cancelledTakerAmount = {}; + this._filledTakerAmount = {}; + this._cancelledTakerAmount = {}; } } diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index 3586919cb..3c93910e9 100644 --- a/packages/0x.js/src/types.ts +++ b/packages/0x.js/src/types.ts @@ -1,4 +1,5 @@ -import BigNumber from 'bignumber.js'; +import { TransactionReceipt } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; import * as Web3 from 'web3'; export enum ZeroExError { @@ -27,6 +28,7 @@ export enum ZeroExError { export enum InternalZeroExError { NoAbiDecoder = 'NO_ABI_DECODER', ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', + WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY', } /** @@ -40,8 +42,7 @@ export interface ECSignature { export type OrderAddresses = [string, string, string, string, string]; -export type OrderValues = [BigNumber, BigNumber, BigNumber, - BigNumber, BigNumber, BigNumber]; +export type OrderValues = [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber]; export type LogEvent = Web3.LogEntryEvent; export interface DecodedLogEvent<ArgsType> { @@ -49,8 +50,8 @@ export interface DecodedLogEvent<ArgsType> { log: LogWithDecodedArgs<ArgsType>; } -export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void; -export type EventWatcherCallback = (log: LogEvent) => void; +export type EventCallback<ArgsType> = (err: null | Error, log?: DecodedLogEvent<ArgsType>) => void; +export type EventWatcherCallback = (err: null | Error, log?: LogEvent) => void; export enum SolidityTypes { Address = 'address', @@ -134,7 +135,10 @@ export interface LogErrorContractEventArgs { errorId: BigNumber; orderHash: string; } -export type ExchangeContractEventArgs = LogFillContractEventArgs|LogCancelContractEventArgs|LogErrorContractEventArgs; +export type ExchangeContractEventArgs = + | LogFillContractEventArgs + | LogCancelContractEventArgs + | LogErrorContractEventArgs; export interface TransferContractEventArgs { _from: string; _to: string; @@ -145,9 +149,21 @@ export interface ApprovalContractEventArgs { _spender: string; _value: BigNumber; } -export type TokenContractEventArgs = TransferContractEventArgs|ApprovalContractEventArgs; -export type ContractEventArgs = ExchangeContractEventArgs|TokenContractEventArgs; -export type ContractEventArg = string|BigNumber; +export interface DepositContractEventArgs { + _owner: string; + _value: BigNumber; +} +export interface WithdrawalContractEventArgs { + _owner: string; + _value: BigNumber; +} +export type TokenContractEventArgs = TransferContractEventArgs | ApprovalContractEventArgs; +export type EtherTokenContractEventArgs = + | TokenContractEventArgs + | DepositContractEventArgs + | WithdrawalContractEventArgs; +export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs; +export type ContractEventArg = string | BigNumber; export interface Order { maker: string; @@ -200,7 +216,14 @@ export enum TokenEvents { Approval = 'Approval', } -export type ContractEvents = TokenEvents|ExchangeEvents; +export enum EtherTokenEvents { + Transfer = 'Transfer', + Approval = 'Approval', + Deposit = 'Deposit', + Withdrawal = 'Withdrawal', +} + +export type ContractEvents = TokenEvents | ExchangeEvents | EtherTokenEvents; export interface IndexedFilterValues { [index: string]: ContractEventArg; @@ -214,9 +237,9 @@ export enum BlockParamLiteral { Pending = 'pending', } -export type BlockParam = BlockParamLiteral|number; +export type BlockParam = BlockParamLiteral | number; -export interface SubscriptionOpts { +export interface BlockRange { fromBlock: BlockParam; toBlock: BlockParam; } @@ -224,7 +247,7 @@ export interface SubscriptionOpts { export type DoneCallback = (err?: Error) => void; export interface OrderCancellationRequest { - order: Order|SignedOrder; + order: Order | SignedOrder; takerTokenCancelAmount: BigNumber; } @@ -234,6 +257,7 @@ export interface OrderFillRequest { } export type AsyncMethod = (...args: any[]) => Promise<any>; +export type SyncMethod = (...args: any[]) => any; /** * We re-export the `Web3.Provider` type specified in the Web3 Typescript typings @@ -266,8 +290,8 @@ export interface OrderStateWatcherConfig { * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 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 * tokenRegistryContractAddress: The address of a token registry contract to use - * etherTokenContractAddress: The address of an ether token contract to use * tokenTransferProxyContractAddress: The address of the token transfer proxy contract to use * orderWatcherConfig: All the configs related to the orderWatcher */ @@ -275,8 +299,8 @@ export interface ZeroExConfig { networkId: number; gasPrice?: BigNumber; exchangeContractAddress?: string; + zrxContractAddress?: string; tokenRegistryContractAddress?: string; - etherTokenContractAddress?: string; tokenTransferProxyContractAddress?: string; orderWatcherConfig?: OrderStateWatcherConfig; } @@ -295,10 +319,10 @@ export interface DecodedLogArgs { export interface LogWithDecodedArgs<ArgsType> extends Web3.DecodedLogEntry<ArgsType> {} export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt { - logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>; + logs: Array<LogWithDecodedArgs<DecodedLogArgs> | Web3.LogEntry>; } -export type ArtifactContractName = 'ZRX'|'TokenTransferProxy'|'TokenRegistry'|'Token'|'Exchange'|'EtherToken'; +export type ArtifactContractName = 'ZRX' | 'TokenTransferProxy' | 'TokenRegistry' | 'Token' | 'Exchange' | 'EtherToken'; export interface Artifact { contract_name: ArtifactContractName; @@ -382,31 +406,7 @@ export interface OrderStateInvalid { error: ExchangeContractErrs; } -export type OrderState = OrderStateValid|OrderStateInvalid; - -export type OnOrderStateChangeCallback = (orderState: OrderState) => void; +export type OrderState = OrderStateValid | OrderStateInvalid; -export interface TxData { - from?: string; - gas?: number; - gasPrice?: BigNumber; - nonce?: number; -} - -export interface TxDataPayable extends TxData { - value?: BigNumber; -} - -export interface TransactionReceipt { - blockHash: string; - blockNumber: number; - transactionHash: string; - transactionIndex: number; - from: string; - to: string; - status: null|0|1; - cumulativeGasUsed: number; - gasUsed: number; - contractAddress: string|null; - logs: Web3.LogEntry[]; -} // tslint:disable:max-file-line-count +export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void; +// tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/utils/abi_decoder.ts b/packages/0x.js/src/utils/abi_decoder.ts index f26b057f0..bbd2a0b1d 100644 --- a/packages/0x.js/src/utils/abi_decoder.ts +++ b/packages/0x.js/src/utils/abi_decoder.ts @@ -1,14 +1,14 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as Web3 from 'web3'; import * as SolidityCoder from 'web3/lib/solidity/coder'; -import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types'; +import { AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes } from '../types'; export class AbiDecoder { - private savedABIs: Web3.AbiDefinition[] = []; - private methodIds: {[signatureHash: string]: Web3.EventAbi} = {}; - private static padZeros(address: string) { + private _savedABIs: Web3.AbiDefinition[] = []; + private _methodIds: { [signatureHash: string]: Web3.EventAbi } = {}; + private static _padZeros(address: string) { let formatted = address; if (_.startsWith(formatted, '0x')) { formatted = formatted.slice(2); @@ -18,13 +18,14 @@ export class AbiDecoder { return `0x${formatted}`; } constructor(abiArrays: Web3.AbiDefinition[][]) { - _.map(abiArrays, this.addABI.bind(this)); + _.map(abiArrays, this._addABI.bind(this)); } // This method can only decode logs from the 0x & ERC20 smart contracts public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>( - log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog { + log: Web3.LogEntry, + ): LogWithDecodedArgs<ArgsType> | RawLog { const methodId = log.topics[0]; - const event = this.methodIds[methodId]; + const event = this._methodIds[methodId]; if (_.isUndefined(event)) { return log; } @@ -41,10 +42,12 @@ export class AbiDecoder { // Indexed parameters are stored in topics. Non-indexed ones in decodedData let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++]; if (param.type === SolidityTypes.Address) { - value = AbiDecoder.padZeros(new BigNumber(value).toString(16)); - } else if (param.type === SolidityTypes.Uint256 || - param.type === SolidityTypes.Uint8 || - param.type === SolidityTypes.Uint) { + value = AbiDecoder._padZeros(new BigNumber(value).toString(16)); + } else if ( + param.type === SolidityTypes.Uint256 || + param.type === SolidityTypes.Uint8 || + param.type === SolidityTypes.Uint + ) { value = new BigNumber(value); } decodedParams[param.name] = value; @@ -56,14 +59,14 @@ export class AbiDecoder { args: decodedParams, }; } - private addABI(abiArray: Web3.AbiDefinition[]): void { + private _addABI(abiArray: Web3.AbiDefinition[]): void { _.map(abiArray, (abi: Web3.AbiDefinition) => { if (abi.type === AbiType.Event) { const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`; const signatureHash = new Web3().sha3(signature); - this.methodIds[signatureHash] = abi; + this._methodIds[signatureHash] = abi; } }); - this.savedABIs = this.savedABIs.concat(abiArray); + this._savedABIs = this._savedABIs.concat(abiArray); } } diff --git a/packages/0x.js/src/utils/assert.ts b/packages/0x.js/src/utils/assert.ts index 4cf6caf77..c21f2dbca 100644 --- a/packages/0x.js/src/utils/assert.ts +++ b/packages/0x.js/src/utils/assert.ts @@ -1,14 +1,14 @@ -import {assert as sharedAssert} from '@0xproject/assert'; -import {Schema, SchemaValidator} from '@0xproject/json-schemas'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { assert as sharedAssert } from '@0xproject/assert'; +// We need those two unused imports because they're actually used by sharedAssert which gets injected here +// tslint:disable-next-line:no-unused-variable +import { Schema } from '@0xproject/json-schemas'; +// tslint:disable-next-line:no-unused-variable +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import * as Web3 from 'web3'; -import {ECSignature} from '../types'; -import {signatureUtils} from '../utils/signature_utils'; - -const HEX_REGEX = /^0x[0-9A-F]*$/i; +import { ECSignature } from '../types'; +import { signatureUtils } from '../utils/signature_utils'; export const assert = { ...sharedAssert, @@ -16,11 +16,15 @@ export const assert = { const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress); this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`); }, - async isSenderAddressAsync(variableName: string, senderAddressHex: string, - web3Wrapper: Web3Wrapper): Promise<void> { + async isSenderAddressAsync( + variableName: string, + senderAddressHex: string, + web3Wrapper: Web3Wrapper, + ): Promise<void> { sharedAssert.isETHAddressHex(variableName, senderAddressHex); const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex); - sharedAssert.assert(isSenderAddressAvailable, + sharedAssert.assert( + isSenderAddressAvailable, `Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`, ); }, diff --git a/packages/0x.js/src/utils/class_utils.ts b/packages/0x.js/src/utils/class_utils.ts deleted file mode 100644 index 04e60ee57..000000000 --- a/packages/0x.js/src/utils/class_utils.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as _ from 'lodash'; - -export const classUtils = { - // This is useful for classes that have nested methods. Nested methods don't get bound out of the box. - bindAll(self: any, exclude: string[] = ['contructor'], thisArg?: any): void { - for (const key of Object.getOwnPropertyNames(self)) { - const val = self[key]; - if (!_.includes(exclude, key)) { - if (_.isFunction(val)) { - self[key] = val.bind(thisArg || self); - } else if (_.isObject(val)) { - classUtils.bindAll(val, exclude, self); - } - } - } - return self; - }, -}; diff --git a/packages/0x.js/src/utils/constants.ts b/packages/0x.js/src/utils/constants.ts index 3de3f5bc1..06beec8e2 100644 --- a/packages/0x.js/src/utils/constants.ts +++ b/packages/0x.js/src/utils/constants.ts @@ -1,4 +1,4 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const constants = { NULL_ADDRESS: '0x0000000000000000000000000000000000000000', @@ -6,6 +6,7 @@ export const constants = { MAX_DIGITS_IN_UNSIGNED_256_INT: 78, INVALID_JUMP_PATTERN: 'invalid JUMP at', OUT_OF_GAS_PATTERN: 'out of gas', + INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string', UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), DEFAULT_BLOCK_POLLING_INTERVAL: 1000, }; diff --git a/packages/0x.js/src/utils/decorators.ts b/packages/0x.js/src/utils/decorators.ts index 1760d8872..f774d734e 100644 --- a/packages/0x.js/src/utils/decorators.ts +++ b/packages/0x.js/src/utils/decorators.ts @@ -1,37 +1,91 @@ import * as _ from 'lodash'; -import {AsyncMethod, ZeroExError} from '../types'; +import { AsyncMethod, SyncMethod, ZeroExError } from '../types'; -import {constants} from './constants'; +import { constants } from './constants'; -export const decorators = { - /** - * Source: https://stackoverflow.com/a/29837695/3546986 - */ - contractCallErrorHandler(target: object, - key: string|symbol, - descriptor: TypedPropertyDescriptor<AsyncMethod>, - ): TypedPropertyDescriptor<AsyncMethod> { - const originalMethod = (descriptor.value as AsyncMethod); +type ErrorTransformer = (err: Error) => Error; + +const contractCallErrorTransformer = (error: Error) => { + if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) { + return new Error(ZeroExError.InvalidJump); + } + if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) { + return new Error(ZeroExError.OutOfGas); + } + return 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'; + return new Error(errMsg); + } + return error; +}; + +/** + * Source: https://stackoverflow.com/a/29837695/3546986 + */ +const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { + const asyncErrorHandlingDecorator = ( + target: object, + key: string | symbol, + descriptor: TypedPropertyDescriptor<AsyncMethod>, + ) => { + const originalMethod = descriptor.value as AsyncMethod; // Do not use arrow syntax here. Use a function expression in // order to use the correct value of `this` in this method // tslint:disable-next-line:only-arrow-functions - descriptor.value = async function(...args: any[]) { + descriptor.value = async function(...args: any[]) { try { const result = await originalMethod.apply(this, args); return result; } catch (error) { - if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) { - throw new Error(ZeroExError.InvalidJump); - } - if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) { - throw new Error(ZeroExError.OutOfGas); - } - throw error; + const transformedError = errorTransformer(error); + throw transformedError; } }; return descriptor; - }, + }; + + return asyncErrorHandlingDecorator; +}; + +const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { + const syncErrorHandlingDecorator = ( + target: object, + key: string | symbol, + descriptor: TypedPropertyDescriptor<SyncMethod>, + ) => { + const originalMethod = descriptor.value as SyncMethod; + + // Do not use arrow syntax here. Use a function expression in + // order to use the correct value of `this` in this method + // tslint:disable-next-line:only-arrow-functions + descriptor.value = function(...args: any[]) { + try { + const result = originalMethod.apply(this, args); + return result; + } catch (error) { + const transformedError = errorTransformer(error); + throw transformedError; + } + }; + + return descriptor; + }; + + return syncErrorHandlingDecorator; +}; + +// _.flow(f, g) = f ∘ g +const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer); + +export const decorators = { + asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer), + syncZeroExErrorHandler: syncErrorHandlerFactory(zeroExErrorTransformer), }; diff --git a/packages/0x.js/src/utils/exchange_transfer_simulator.ts b/packages/0x.js/src/utils/exchange_transfer_simulator.ts index 2574bd9ac..662cd210c 100644 --- a/packages/0x.js/src/utils/exchange_transfer_simulator.ts +++ b/packages/0x.js/src/utils/exchange_transfer_simulator.ts @@ -1,9 +1,9 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {TokenWrapper} from '../contract_wrappers/token_wrapper'; -import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; -import {BlockParamLiteral, ExchangeContractErrs, TradeSide, TransferType} from '../types'; +import { TokenWrapper } from '../contract_wrappers/token_wrapper'; +import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; +import { BlockParamLiteral, ExchangeContractErrs, TradeSide, TransferType } from '../types'; enum FailureReason { Balance = 'balance', @@ -34,16 +34,19 @@ const ERR_MSG_MAPPING = { }; export class ExchangeTransferSimulator { - private store: BalanceAndProxyAllowanceLazyStore; - private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; - private static throwValidationError(failureReason: FailureReason, tradeSide: TradeSide, - transferType: TransferType): never { + private _store: BalanceAndProxyAllowanceLazyStore; + private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; + private static _throwValidationError( + failureReason: FailureReason, + tradeSide: TradeSide, + transferType: TransferType, + ): never { const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; throw new Error(errMsg); } constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { - this.store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock); - this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock); + this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; } /** * Simulates transferFrom call performed by a proxy @@ -54,36 +57,50 @@ export class ExchangeTransferSimulator { * @param tradeSide Is Maker/Taker transferring * @param transferType Is it a fee payment or a value transfer */ - public async transferFromAsync(tokenAddress: string, from: string, to: string, - amountInBaseUnits: BigNumber, tradeSide: TradeSide, - transferType: TransferType): Promise<void> { - const balance = await this.store.getBalanceAsync(tokenAddress, from); - const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, from); + public async transferFromAsync( + tokenAddress: string, + from: string, + to: string, + amountInBaseUnits: BigNumber, + tradeSide: TradeSide, + transferType: TransferType, + ): Promise<void> { + const balance = await this._store.getBalanceAsync(tokenAddress, from); + const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from); if (proxyAllowance.lessThan(amountInBaseUnits)) { - ExchangeTransferSimulator.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType); + ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType); } if (balance.lessThan(amountInBaseUnits)) { - ExchangeTransferSimulator.throwValidationError(FailureReason.Balance, tradeSide, transferType); + ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType); } - await this.decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits); - await this.decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits); - await this.increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); + await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits); + await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits); + await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); } - private async decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string, - amountInBaseUnits: BigNumber): Promise<void> { - const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, userAddress); - if (!proxyAllowance.eq(this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - this.store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); + private async _decreaseProxyAllowanceAsync( + tokenAddress: string, + userAddress: string, + amountInBaseUnits: BigNumber, + ): Promise<void> { + const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress); + if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { + this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); } } - private async increaseBalanceAsync(tokenAddress: string, userAddress: string, - amountInBaseUnits: BigNumber): Promise<void> { - const balance = await this.store.getBalanceAsync(tokenAddress, userAddress); - this.store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits)); + private async _increaseBalanceAsync( + tokenAddress: string, + userAddress: string, + amountInBaseUnits: BigNumber, + ): Promise<void> { + const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); + this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits)); } - private async decreaseBalanceAsync(tokenAddress: string, userAddress: string, - amountInBaseUnits: BigNumber): Promise<void> { - const balance = await this.store.getBalanceAsync(tokenAddress, userAddress); - this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); + private async _decreaseBalanceAsync( + tokenAddress: string, + userAddress: string, + amountInBaseUnits: BigNumber, + ): Promise<void> { + const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); + this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); } } diff --git a/packages/0x.js/src/utils/filter_utils.ts b/packages/0x.js/src/utils/filter_utils.ts index 57c3ee71c..97205ace3 100644 --- a/packages/0x.js/src/utils/filter_utils.ts +++ b/packages/0x.js/src/utils/filter_utils.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import * as uuid from 'uuid/v4'; import * as Web3 from 'web3'; -import {ContractEvents, IndexedFilterValues, SubscriptionOpts} from '../types'; +import { BlockRange, ContractEvents, IndexedFilterValues } from '../types'; const TOPIC_LENGTH = 32; @@ -12,10 +12,14 @@ export const filterUtils = { generateUUID(): string { return uuid(); }, - getFilter(address: string, eventName: ContractEvents, - indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi, - subscriptionOpts?: SubscriptionOpts): Web3.FilterObject { - const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi; + getFilter( + address: string, + eventName: ContractEvents, + indexFilterValues: IndexedFilterValues, + abi: Web3.ContractAbi, + blockRange?: BlockRange, + ): Web3.FilterObject { + const eventAbi = _.find(abi, { name: eventName }) as Web3.EventAbi; const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName); const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature)); const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues); @@ -24,9 +28,9 @@ export const filterUtils = { address, topics, }; - if (!_.isUndefined(subscriptionOpts)) { + if (!_.isUndefined(blockRange)) { filter = { - ...subscriptionOpts, + ...blockRange, ...filter, }; } @@ -37,8 +41,8 @@ export const filterUtils = { const signature = `${eventAbi.name}(${types.join(',')})`; return signature; }, - getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string|null> { - const topics: Array<string|null> = []; + getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string | null> { + const topics: Array<string | null> = []; for (const eventInput of abi.inputs) { if (!eventInput.indexed) { continue; @@ -65,12 +69,12 @@ export const filterUtils = { } return true; }, - matchesTopics(logTopics: string[], filterTopics: Array<string[]|string|null>): boolean { + matchesTopics(logTopics: string[], filterTopics: Array<string[] | string | null>): boolean { const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils)); const matchesTopics = _.every(matchesTopic); return matchesTopics; }, - matchesTopic(logTopic: string, filterTopic: string[]|string|null): boolean { + matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean { if (_.isArray(filterTopic)) { return _.includes(filterTopic, logTopic); } diff --git a/packages/0x.js/src/utils/interval_utils.ts b/packages/0x.js/src/utils/interval_utils.ts deleted file mode 100644 index 62b79f2f5..000000000 --- a/packages/0x.js/src/utils/interval_utils.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as _ from 'lodash'; - -export const intervalUtils = { - setAsyncExcludingInterval(fn: () => Promise<void>, intervalMs: number) { - let locked = false; - const intervalId = setInterval(async () => { - if (locked) { - return; - } else { - locked = true; - await fn(); - locked = false; - } - }, intervalMs); - return intervalId; - }, - clearAsyncExcludingInterval(intervalId: NodeJS.Timer): void { - clearInterval(intervalId); - }, -}; diff --git a/packages/0x.js/src/utils/order_state_utils.ts b/packages/0x.js/src/utils/order_state_utils.ts index 6b7f811ae..b7a55ff42 100644 --- a/packages/0x.js/src/utils/order_state_utils.ts +++ b/packages/0x.js/src/utils/order_state_utils.ts @@ -1,31 +1,26 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import * as Web3 from 'web3'; -import {ZeroEx} from '../0x'; -import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; -import {TokenWrapper} from '../contract_wrappers/token_wrapper'; -import {RemainingFillableCalculator} from '../order_watcher/remaining_fillable_calculator'; -import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; -import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store'; +import { ZeroEx } from '../0x'; +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { RemainingFillableCalculator } from '../order_watcher/remaining_fillable_calculator'; +import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; +import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store'; import { ExchangeContractErrs, - MethodOpts, OrderRelevantState, OrderState, OrderStateInvalid, OrderStateValid, SignedOrder, } from '../types'; -import {constants} from '../utils/constants'; -import {utils} from '../utils/utils'; const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001; export class OrderStateUtils { - private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore; - private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore; - private static validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { + private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore; + private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore; + private static _validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add( orderRelevantState.filledTakerTokenAmount, ); @@ -49,23 +44,28 @@ export class OrderStateUtils { } } const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount - .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) - .dividedBy(signedOrder.makerTokenAmount); - if (orderRelevantState.remainingFillableTakerTokenAmount - .lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) { + .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) + .dividedBy(signedOrder.makerTokenAmount); + if ( + orderRelevantState.remainingFillableTakerTokenAmount.lessThan( + minFillableTakerTokenAmountWithinNoRoundingErrorRange, + ) + ) { throw new Error(ExchangeContractErrs.OrderFillRoundingError); } } - constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore, - orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) { - this.balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore; - this.orderFilledCancelledLazyStore = orderFilledCancelledLazyStore; + constructor( + balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore, + orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore, + ) { + this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore; + this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore; } public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> { const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder); try { - OrderStateUtils.validateIfOrderIsValid(signedOrder, orderRelevantState); + OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState); const orderState: OrderStateValid = { isValid: true, orderHash, @@ -86,40 +86,47 @@ export class OrderStateUtils { // If we pass it from the instantiator - there is no opportunity to get it there // because JS doesn't support async constructors. // Moreover - it's cached under the hood so it's equivalent to an async constructor. - const exchange = (this.orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper; + const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper; const zrxTokenAddress = exchange.getZRXTokenAddress(); const orderHash = ZeroEx.getOrderHashHex(signedOrder); - const makerBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync( - signedOrder.makerTokenAddress, signedOrder.maker, + const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync( + signedOrder.makerTokenAddress, + signedOrder.maker, ); - const makerProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( - signedOrder.makerTokenAddress, signedOrder.maker, + const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( + signedOrder.makerTokenAddress, + signedOrder.maker, ); - const makerFeeBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync( - zrxTokenAddress, signedOrder.maker, + const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync( + zrxTokenAddress, + signedOrder.maker, ); - const makerFeeProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( - zrxTokenAddress, signedOrder.maker, + const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( + zrxTokenAddress, + signedOrder.maker, ); - const filledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash); - const cancelledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getCancelledTakerAmountAsync( + const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash); + const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync( orderHash, ); const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash); const totalMakerTokenAmount = signedOrder.makerTokenAmount; const totalTakerTokenAmount = signedOrder.takerTokenAmount; const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); - const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount) - .dividedToIntegerBy(totalTakerTokenAmount); + const remainingMakerTokenAmount = remainingTakerTokenAmount + .times(totalMakerTokenAmount) + .dividedToIntegerBy(totalTakerTokenAmount); const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]); const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress; - const remainingFillableCalculator = new RemainingFillableCalculator(signedOrder, - isMakerTokenZRX, - transferrableMakerTokenAmount, - transferrableFeeTokenAmount, - remainingMakerTokenAmount); + const remainingFillableCalculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableFeeTokenAmount, + remainingMakerTokenAmount, + ); const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable(); const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable(); const orderRelevantState = { diff --git a/packages/0x.js/src/utils/order_validation_utils.ts b/packages/0x.js/src/utils/order_validation_utils.ts index d514483e0..917d414c8 100644 --- a/packages/0x.js/src/utils/order_validation_utils.ts +++ b/packages/0x.js/src/utils/order_validation_utils.ts @@ -1,20 +1,20 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {ZeroEx} from '../0x'; -import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; -import {TokenWrapper} from '../contract_wrappers/token_wrapper'; -import {ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError} from '../types'; -import {constants} from '../utils/constants'; -import {utils} from '../utils/utils'; +import { ZeroEx } from '../0x'; +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError } from '../types'; +import { constants } from '../utils/constants'; +import { utils } from '../utils/utils'; -import {ExchangeTransferSimulator} from './exchange_transfer_simulator'; +import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; export class OrderValidationUtils { - private tokenWrapper: TokenWrapper; - private exchangeWrapper: ExchangeWrapper; + private _exchangeWrapper: ExchangeWrapper; public static validateCancelOrderThrowIfInvalid( - order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber, + order: Order, + cancelTakerTokenAmount: BigNumber, + unavailableTakerTokenAmount: BigNumber, ): void { if (cancelTakerTokenAmount.eq(0)) { throw new Error(ExchangeContractErrs.OrderCancelAmountZero); @@ -28,102 +28,135 @@ export class OrderValidationUtils { } } public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string, + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + senderAddress: string, + zrxTokenAddress: string, ): Promise<void> { - const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount( + const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, ); await exchangeTradeEmulator.transferFromAsync( - signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount, - TradeSide.Maker, TransferType.Trade, + signedOrder.makerTokenAddress, + signedOrder.maker, + senderAddress, + fillMakerTokenAmount, + TradeSide.Maker, + TransferType.Trade, ); await exchangeTradeEmulator.transferFromAsync( - signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount, - TradeSide.Taker, TransferType.Trade, + signedOrder.takerTokenAddress, + senderAddress, + signedOrder.maker, + fillTakerTokenAmount, + TradeSide.Taker, + TransferType.Trade, ); - const makerFeeAmount = OrderValidationUtils.getPartialAmount( + const makerFeeAmount = OrderValidationUtils._getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerFee, ); await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker, + zrxTokenAddress, + signedOrder.maker, + signedOrder.feeRecipient, + makerFeeAmount, + TradeSide.Maker, TransferType.Fee, ); - const takerFeeAmount = OrderValidationUtils.getPartialAmount( + const takerFeeAmount = OrderValidationUtils._getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.takerFee, ); await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker, + zrxTokenAddress, + senderAddress, + signedOrder.feeRecipient, + takerFeeAmount, + TradeSide.Taker, TransferType.Fee, ); } - private static validateRemainingFillAmountNotZeroOrThrow( - takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber, + private static _validateRemainingFillAmountNotZeroOrThrow( + takerTokenAmount: BigNumber, + unavailableTakerTokenAmount: BigNumber, ) { if (takerTokenAmount.eq(unavailableTakerTokenAmount)) { throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); } } - private static validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) { + private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) { const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { throw new Error(ExchangeContractErrs.OrderFillExpired); } } - private static getPartialAmount(numerator: BigNumber, denominator: BigNumber, - target: BigNumber): BigNumber { + private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { const fillMakerTokenAmount = numerator - .mul(target) - .div(denominator) - .round(0); + .mul(target) + .div(denominator) + .round(0); return fillMakerTokenAmount; } - constructor(tokenWrapper: TokenWrapper, exchangeWrapper: ExchangeWrapper) { - this.tokenWrapper = tokenWrapper; - this.exchangeWrapper = exchangeWrapper; + constructor(exchangeWrapper: ExchangeWrapper) { + this._exchangeWrapper = exchangeWrapper; } public async validateOrderFillableOrThrowAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string, - expectedFillTakerTokenAmount?: BigNumber): Promise<void> { + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + zrxTokenAddress: string, + expectedFillTakerTokenAmount?: BigNumber, + ): Promise<void> { const orderHash = utils.getOrderHashHex(signedOrder); - const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); - OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow( - signedOrder.takerTokenAmount, unavailableTakerTokenAmount, + const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( + signedOrder.takerTokenAmount, + unavailableTakerTokenAmount, ); - OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); if (!_.isUndefined(expectedFillTakerTokenAmount)) { fillTakerTokenAmount = expectedFillTakerTokenAmount; } - const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount( + const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, ); await exchangeTradeEmulator.transferFromAsync( - signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount, - TradeSide.Maker, TransferType.Trade, - ); - const makerFeeAmount = OrderValidationUtils.getPartialAmount( + signedOrder.makerTokenAddress, + signedOrder.maker, + signedOrder.taker, + fillMakerTokenAmount, + TradeSide.Maker, + TransferType.Trade, + ); + const makerFeeAmount = OrderValidationUtils._getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerFee, ); await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, - TradeSide.Maker, TransferType.Fee, + zrxTokenAddress, + signedOrder.maker, + signedOrder.feeRecipient, + makerFeeAmount, + TradeSide.Maker, + TransferType.Fee, ); } public async validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, takerAddress: string, - zrxTokenAddress: string): Promise<BigNumber> { + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + zrxTokenAddress: string, + ): Promise<BigNumber> { if (fillTakerTokenAmount.eq(0)) { throw new Error(ExchangeContractErrs.OrderFillAmountZero); } @@ -131,24 +164,31 @@ export class OrderValidationUtils { if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) { throw new Error(ZeroExError.InvalidSignature); } - const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); - OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow( - signedOrder.takerTokenAmount, unavailableTakerTokenAmount, + const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( + signedOrder.takerTokenAmount, + unavailableTakerTokenAmount, ); if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) { throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); } - OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); - const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ? - remainingTakerTokenAmount : - fillTakerTokenAmount; + const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) + ? remainingTakerTokenAmount + : fillTakerTokenAmount; await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress, + exchangeTradeEmulator, + signedOrder, + filledTakerTokenAmount, + takerAddress, + zrxTokenAddress, ); - const wouldRoundingErrorOccur = await this.exchangeWrapper.isRoundingErrorAsync( - filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, + const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync( + filledTakerTokenAmount, + signedOrder.takerTokenAmount, + signedOrder.makerTokenAmount, ); if (wouldRoundingErrorOccur) { throw new Error(ExchangeContractErrs.OrderFillRoundingError); @@ -156,10 +196,18 @@ export class OrderValidationUtils { return filledTakerTokenAmount; } public async validateFillOrKillOrderThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> { + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + zrxTokenAddress: string, + ): Promise<void> { const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, ); if (filledTakerTokenAmount !== fillTakerTokenAmount) { throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount); diff --git a/packages/0x.js/src/utils/signature_utils.ts b/packages/0x.js/src/utils/signature_utils.ts index aaf04e7b0..b0f1d61ef 100644 --- a/packages/0x.js/src/utils/signature_utils.ts +++ b/packages/0x.js/src/utils/signature_utils.ts @@ -1,6 +1,6 @@ import * as ethUtil from 'ethereumjs-util'; -import {ECSignature} from '../types'; +import { ECSignature } from '../types'; export const signatureUtils = { isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean { @@ -11,7 +11,8 @@ export const signatureUtils = { msgHashBuff, signature.v, ethUtil.toBuffer(signature.r), - ethUtil.toBuffer(signature.s)); + ethUtil.toBuffer(signature.s), + ); const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); return retrievedAddress === signerAddress; } catch (err) { @@ -34,7 +35,7 @@ export const signatureUtils = { return ecSignature; }, parseSignatureHexAsRSV(signatureHex: string): ECSignature { - const {v, r, s} = ethUtil.fromRpcSig(signatureHex); + const { v, r, s } = ethUtil.fromRpcSig(signatureHex); const ecSignature: ECSignature = { v, r: ethUtil.bufferToHex(r), diff --git a/packages/0x.js/src/utils/utils.ts b/packages/0x.js/src/utils/utils.ts index 04ae34aac..e42a1a853 100644 --- a/packages/0x.js/src/utils/utils.ts +++ b/packages/0x.js/src/utils/utils.ts @@ -1,10 +1,10 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import BN = require('bn.js'); import * as ethABI from 'ethereumjs-abi'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import {Order, SignedOrder, SolidityTypes} from '../types'; +import { Order, SignedOrder, SolidityTypes } from '../types'; export const utils = { /** @@ -29,20 +29,35 @@ export const utils = { spawnSwitchErr(name: string, value: any): Error { return new Error(`Unexpected switch value: ${value} encountered for ${name}`); }, - getOrderHashHex(order: Order|SignedOrder): string { + getOrderHashHex(order: Order | SignedOrder): string { const orderParts = [ - {value: order.exchangeContractAddress, type: SolidityTypes.Address}, - {value: order.maker, type: SolidityTypes.Address}, - {value: order.taker, type: SolidityTypes.Address}, - {value: order.makerTokenAddress, type: SolidityTypes.Address}, - {value: order.takerTokenAddress, type: SolidityTypes.Address}, - {value: order.feeRecipient, type: SolidityTypes.Address}, - {value: utils.bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.Uint256}, - {value: utils.bigNumberToBN(order.takerTokenAmount), type: SolidityTypes.Uint256}, - {value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.Uint256}, - {value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.Uint256}, - {value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.Uint256}, - {value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256}, + { value: order.exchangeContractAddress, type: SolidityTypes.Address }, + { value: order.maker, type: SolidityTypes.Address }, + { value: order.taker, type: SolidityTypes.Address }, + { value: order.makerTokenAddress, type: SolidityTypes.Address }, + { value: order.takerTokenAddress, type: SolidityTypes.Address }, + { value: order.feeRecipient, type: SolidityTypes.Address }, + { + value: utils.bigNumberToBN(order.makerTokenAmount), + type: SolidityTypes.Uint256, + }, + { + value: utils.bigNumberToBN(order.takerTokenAmount), + type: SolidityTypes.Uint256, + }, + { + value: utils.bigNumberToBN(order.makerFee), + type: SolidityTypes.Uint256, + }, + { + value: utils.bigNumberToBN(order.takerFee), + type: SolidityTypes.Uint256, + }, + { + value: utils.bigNumberToBN(order.expirationUnixTimestampSec), + type: SolidityTypes.Uint256, + }, + { value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256 }, ]; const types = _.map(orderParts, o => o.type); const values = _.map(orderParts, o => o.value); diff --git a/packages/0x.js/test/0x.js_test.ts b/packages/0x.js/test/0x.js_test.ts index 6b7a70699..5bc2c149c 100644 --- a/packages/0x.js/test/0x.js_test.ts +++ b/packages/0x.js/test/0x.js_test.ts @@ -1,18 +1,18 @@ -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; import 'mocha'; import * as Sinon from 'sinon'; -import {ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx, ZeroExError} from '../src'; +import { ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx } from '../src'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); chaiSetup.configure(); const expect = chai.expect; @@ -41,11 +41,11 @@ describe('ZeroEx library', () => { // Check that all nested web3 wrapper instances return the updated provider const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider(); - expect((nestedWeb3WrapperProvider).zeroExTestId).to.be.a('number'); + expect(nestedWeb3WrapperProvider.zeroExTestId).to.be.a('number'); const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider(); - expect((exchangeWeb3WrapperProvider).zeroExTestId).to.be.a('number'); + expect(exchangeWeb3WrapperProvider.zeroExTestId).to.be.a('number'); const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider(); - expect((tokenRegistryWeb3WrapperProvider).zeroExTestId).to.be.a('number'); + expect(tokenRegistryWeb3WrapperProvider.zeroExTestId).to.be.a('number'); }); }); describe('#isValidSignature', () => { @@ -58,22 +58,25 @@ describe('ZeroEx library', () => { s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', }; const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; - it('should return false if the data doesn\'t pertain to the signature & address', async () => { + it("should return false if the data doesn't pertain to the signature & address", async () => { expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false(); return expect( (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address), ).to.become(false); }); - it('should return false if the address doesn\'t pertain to the signature & data', async () => { + it("should return false if the address doesn't pertain to the signature & data", async () => { const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false(); return expect( - (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature, - validUnrelatedAddress), + (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync( + dataHex, + signature, + validUnrelatedAddress, + ), ).to.become(false); }); - it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => { - const wrongSignature = _.assign({}, signature, {v: 28}); + it("should return false if the signature doesn't pertain to the dataHex & address", async () => { + const wrongSignature = _.assign({}, signature, { v: 28 }); expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false(); return expect( (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, wrongSignature, address), @@ -82,9 +85,9 @@ describe('ZeroEx library', () => { it('should return true if the signature does pertain to the dataHex & address', async () => { const isValidSignatureLocal = ZeroEx.isValidSignature(dataHex, signature, address); expect(isValidSignatureLocal).to.be.true(); - const isValidSignatureOnContract = await (zeroEx.exchange as any) - ._isValidSignatureUsingContractCallAsync(dataHex, signature, address); - return expect(isValidSignatureOnContract).to.be.true(); + return expect( + (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature, address), + ).to.become(true); }); }); describe('#generateSalt', () => { @@ -114,6 +117,13 @@ describe('ZeroEx library', () => { }); }); describe('#toUnitAmount', () => { + it('should throw if invalid baseUnit amount supplied as argument', () => { + const invalidBaseUnitAmount = new BigNumber(1000000000.4); + const decimals = 6; + expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals)).to.throw( + 'amount should be in baseUnits (no decimals), found value: 1000000000.4', + ); + }); it('Should return the expected unit amount for the decimals passed in', () => { const baseUnitAmount = new BigNumber(1000000000); const decimals = 6; @@ -130,6 +140,13 @@ describe('ZeroEx library', () => { const expectedUnitAmount = new BigNumber(1000000000); expect(baseUnitAmount).to.be.bignumber.equal(expectedUnitAmount); }); + it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => { + const unitAmount = new BigNumber(0.823091); + const decimals = 5; + expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals)).to.throw( + 'Invalid unit amount: 0.823091 - Too many decimal places', + ); + }); }); describe('#getOrderHashHex', () => { const expectedOrderHash = '0x39da987067a3c9e5f1617694f1301326ba8c8b0498ebef5df4863bed394e3c83'; @@ -152,6 +169,15 @@ describe('ZeroEx library', () => { const orderHash = ZeroEx.getOrderHashHex(order); expect(orderHash).to.be.equal(expectedOrderHash); }); + it('throws a readable error message if taker format is invalid', async () => { + const orderWithInvalidtakerFormat = { + ...order, + taker: (null as any) as string, + }; + const expectedErrorMessage = + 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS'; + expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage); + }); }); describe('#signOrderHashAsync', () => { let stubs: Sinon.SinonStub[] = []; @@ -177,16 +203,15 @@ describe('ZeroEx library', () => { }); it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => { const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004'; - // tslint:disable-next-line: max-line-length - const signature = '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b'; + const signature = + '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b'; const expectedECSignature = { v: 27, r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3', s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02', }; stubs = [ - Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync') - .returns(Promise.resolve(signature)), + Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)), Sinon.stub(ZeroEx, 'isValidSignature').returns(true), ]; @@ -195,16 +220,15 @@ describe('ZeroEx library', () => { }); it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => { const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7'; - // tslint:disable-next-line: max-line-length - const signature = '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960'; + const signature = + '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960'; const expectedECSignature = { v: 27, r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0', s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960', }; stubs = [ - Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync') - .returns(Promise.resolve(signature)), + Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)), Sinon.stub(ZeroEx, 'isValidSignature').returns(true), ]; @@ -244,22 +268,15 @@ describe('ZeroEx library', () => { const zeroExWithWrongExchangeAddress = new ZeroEx(web3.currentProvider, zeroExConfig); expect(zeroExWithWrongExchangeAddress.exchange.getContractAddress()).to.be.equal(ZeroEx.NULL_ADDRESS); }); - it('allows to specify ether token contract address', async () => { - const zeroExConfig = { - etherTokenContractAddress: ZeroEx.NULL_ADDRESS, - networkId: constants.TESTRPC_NETWORK_ID, - }; - const zeroExWithWrongEtherTokenAddress = new ZeroEx(web3.currentProvider, zeroExConfig); - expect(zeroExWithWrongEtherTokenAddress.etherToken.getContractAddress()).to.be.equal(ZeroEx.NULL_ADDRESS); - }); it('allows to specify token registry token contract address', async () => { const zeroExConfig = { tokenRegistryContractAddress: ZeroEx.NULL_ADDRESS, networkId: constants.TESTRPC_NETWORK_ID, }; const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig); - expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()) - .to.be.equal(ZeroEx.NULL_ADDRESS); + expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()).to.be.equal( + ZeroEx.NULL_ADDRESS, + ); }); }); }); diff --git a/packages/0x.js/test/artifacts_test.ts b/packages/0x.js/test/artifacts_test.ts index f4599a24d..e8ab9aa97 100644 --- a/packages/0x.js/test/artifacts_test.ts +++ b/packages/0x.js/test/artifacts_test.ts @@ -1,14 +1,12 @@ -import * as chai from 'chai'; import * as fs from 'fs'; import HDWalletProvider = require('truffle-hdwallet-provider'); -import {ZeroEx} from '../src'; +import { ZeroEx } from '../src'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; chaiSetup.configure(); -const expect = chai.expect; // Those tests are slower cause they're talking to a remote node const TIMEOUT = 10000; diff --git a/packages/0x.js/test/assert_test.ts b/packages/0x.js/test/assert_test.ts index 9fa7f780f..1f2820070 100644 --- a/packages/0x.js/test/assert_test.ts +++ b/packages/0x.js/test/assert_test.ts @@ -1,11 +1,11 @@ import * as chai from 'chai'; import 'mocha'; -import {ZeroEx} from '../src'; -import {assert} from '../src/utils/assert'; +import { ZeroEx } from '../src'; +import { assert } from '../src/utils/assert'; -import {constants} from './utils/constants'; -import {web3Factory} from './utils/web3_factory'; +import { constants } from './utils/constants'; +import { web3Factory } from './utils/web3_factory'; const expect = chai.expect; @@ -19,22 +19,25 @@ describe('Assertion library', () => { it('throws when address is invalid', async () => { const address = '0xdeadbeef'; const varName = 'address'; - return expect(assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper)) - .to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`); + return expect( + assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper), + ).to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`); }); it('throws when address is unavailable', async () => { const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42'; const varName = 'address'; - return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper)) - .to.be.rejectedWith( - `Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`, - ); + return expect( + assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper), + ).to.be.rejectedWith( + `Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`, + ); }); - it('doesn\'t throw if address is available', async () => { + it("doesn't throw if address is available", async () => { const availableAddress = (await zeroEx.getAvailableAddressesAsync())[0]; const varName = 'address'; - return expect(assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper)) - .to.become(undefined); + return expect( + assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper), + ).to.become(undefined); }); }); }); diff --git a/packages/0x.js/test/ether_token_wrapper_test.ts b/packages/0x.js/test/ether_token_wrapper_test.ts index d3e4439ee..b810fc9f1 100644 --- a/packages/0x.js/test/ether_token_wrapper_test.ts +++ b/packages/0x.js/test/ether_token_wrapper_test.ts @@ -1,18 +1,34 @@ -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import 'mocha'; import * as Web3 from 'web3'; -import {ZeroEx, ZeroExError} from '../src'; +import { + ApprovalContractEventArgs, + BlockParamLiteral, + BlockRange, + DecodedLogEvent, + DepositContractEventArgs, + EtherTokenEvents, + Token, + TransferContractEventArgs, + WithdrawalContractEventArgs, + ZeroEx, + ZeroExError, +} from '../src'; +import { artifacts } from '../src/artifacts'; +import { DoneCallback } from '../src/types'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { reportNodeCallbackErrors } from './utils/report_callback_errors'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); // Since the address depositing/withdrawing ETH/WETH also needs to pay gas costs for the transaction, // a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between @@ -23,24 +39,32 @@ const MAX_REASONABLE_GAS_COST_IN_WEI = 62517; describe('EtherTokenWrapper', () => { let web3: Web3; let zeroEx: ZeroEx; + let tokens: Token[]; let userAddresses: string[]; let addressWithETH: string; let wethContractAddress: string; let depositWeiAmount: BigNumber; let decimalPlaces: number; + 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 () => { web3 = web3Factory.create(); zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig); + tokens = await zeroEx.tokenRegistry.getTokensAsync(); userAddresses = await zeroEx.getAvailableAddressesAsync(); addressWithETH = userAddresses[0]; - wethContractAddress = zeroEx.etherToken.getContractAddress(); + wethContractAddress = (zeroEx.etherToken as any)._getContractAddress(artifacts.EtherTokenArtifact); depositWeiAmount = (zeroEx as any)._web3Wrapper.toWei(new BigNumber(5)); decimalPlaces = 7; + addressWithoutFunds = userAddresses[1]; }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -55,7 +79,7 @@ describe('EtherTokenWrapper', () => { expect(preETHBalance).to.be.bignumber.gt(0); expect(preWETHBalance).to.be.bignumber.equal(0); - const txHash = await zeroEx.etherToken.depositAsync(depositWeiAmount, addressWithETH); + const txHash = await zeroEx.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH); await zeroEx.awaitTransactionMinedAsync(txHash); const postETHBalanceInWei = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH); @@ -73,7 +97,7 @@ describe('EtherTokenWrapper', () => { const overETHBalanceinWei = preETHBalance.add(extraETHBalance); return expect( - zeroEx.etherToken.depositAsync(overETHBalanceinWei, addressWithETH), + zeroEx.etherToken.depositAsync(wethContractAddress, overETHBalanceinWei, addressWithETH), ).to.be.rejectedWith(ZeroExError.InsufficientEthBalanceForDeposit); }); }); @@ -81,7 +105,7 @@ describe('EtherTokenWrapper', () => { it('should successfully withdraw ETH in return for Wrapped ETH tokens', async () => { const ETHBalanceInWei = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH); - await zeroEx.etherToken.depositAsync(depositWeiAmount, addressWithETH); + await zeroEx.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH); const expectedPreETHBalance = ETHBalanceInWei.minus(depositWeiAmount); const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH); @@ -90,7 +114,7 @@ describe('EtherTokenWrapper', () => { expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI); expect(preWETHBalance).to.be.bignumber.equal(depositWeiAmount); - const txHash = await zeroEx.etherToken.withdrawAsync(depositWeiAmount, addressWithETH); + const txHash = await zeroEx.etherToken.withdrawAsync(wethContractAddress, depositWeiAmount, addressWithETH); await zeroEx.awaitTransactionMinedAsync(txHash); const postETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH); @@ -108,8 +132,244 @@ describe('EtherTokenWrapper', () => { const overWETHBalance = preWETHBalance.add(999999999); return expect( - zeroEx.etherToken.withdrawAsync(overWETHBalance, addressWithETH), + zeroEx.etherToken.withdrawAsync(wethContractAddress, overWETHBalance, addressWithETH), ).to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal); }); }); + describe('#subscribe', () => { + const indexFilterValues = {}; + let etherTokenAddress: string; + before(() => { + const tokenUtils = new TokenUtils(tokens); + const etherToken = tokenUtils.getWethTokenOrThrow(); + etherTokenAddress = etherToken.address; + }); + afterEach(() => { + zeroEx.etherToken.unsubscribeAll(); + }); + // Hack: Mocha does not allow a test to be both async and have a `done` callback + // Since we need to await the receipt of the event in the `subscribe` callback, + // we do need both. A hack is to make the top-level async fn w/ a done callback and then + // wrap the rest of the test in an async block + // Source: https://github.com/mochajs/mocha/issues/2407 + it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { + (async () => { + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<TransferContractEventArgs>) => { + expect(logEvent).to.not.be.undefined(); + expect(logEvent.isRemoved).to.be.false(); + expect(logEvent.log.logIndex).to.be.equal(0); + expect(logEvent.log.transactionIndex).to.be.equal(0); + expect(logEvent.log.blockNumber).to.be.a('number'); + const args = logEvent.log.args; + expect(args._from).to.be.equal(addressWithETH); + expect(args._to).to.be.equal(addressWithoutFunds); + expect(args._value).to.be.bignumber.equal(transferAmount); + }, + ); + await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); + zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback); + await zeroEx.token.transferAsync( + etherTokenAddress, + addressWithETH, + addressWithoutFunds, + transferAmount, + ); + })().catch(done); + }); + it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { + (async () => { + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + expect(logEvent).to.not.be.undefined(); + expect(logEvent.isRemoved).to.be.false(); + const args = logEvent.log.args; + expect(args._owner).to.be.equal(addressWithETH); + expect(args._spender).to.be.equal(addressWithoutFunds); + expect(args._value).to.be.bignumber.equal(allowanceAmount); + }, + ); + zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback); + await zeroEx.token.setAllowanceAsync( + etherTokenAddress, + addressWithETH, + addressWithoutFunds, + allowanceAmount, + ); + })().catch(done); + }); + it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => { + (async () => { + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<DepositContractEventArgs>) => { + expect(logEvent).to.not.be.undefined(); + expect(logEvent.isRemoved).to.be.false(); + const args = logEvent.log.args; + expect(args._owner).to.be.equal(addressWithETH); + expect(args._value).to.be.bignumber.equal(depositAmount); + }, + ); + zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback); + await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); + })().catch(done); + }); + it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => { + (async () => { + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => { + expect(logEvent).to.not.be.undefined(); + expect(logEvent.isRemoved).to.be.false(); + const args = logEvent.log.args; + expect(args._owner).to.be.equal(addressWithETH); + expect(args._value).to.be.bignumber.equal(depositAmount); + }, + ); + await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); + zeroEx.etherToken.subscribe( + etherTokenAddress, + EtherTokenEvents.Withdrawal, + indexFilterValues, + callback, + ); + await zeroEx.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH); + })().catch(done); + }); + it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => { + (async () => { + const callbackNeverToBeCalled = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, + ); + zeroEx.etherToken.subscribe( + etherTokenAddress, + EtherTokenEvents.Transfer, + indexFilterValues, + callbackNeverToBeCalled, + ); + const callbackToBeCalled = reportNodeCallbackErrors(done)(); + const newProvider = web3Factory.getRpcProvider(); + zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID); + await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); + zeroEx.etherToken.subscribe( + etherTokenAddress, + EtherTokenEvents.Transfer, + indexFilterValues, + callbackToBeCalled, + ); + await zeroEx.token.transferAsync( + etherTokenAddress, + addressWithETH, + addressWithoutFunds, + transferAmount, + ); + })().catch(done); + }); + it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { + (async () => { + const callbackNeverToBeCalled = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, + ); + await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); + const subscriptionToken = zeroEx.etherToken.subscribe( + etherTokenAddress, + EtherTokenEvents.Transfer, + indexFilterValues, + callbackNeverToBeCalled, + ); + zeroEx.etherToken.unsubscribe(subscriptionToken); + await zeroEx.token.transferAsync( + etherTokenAddress, + addressWithETH, + addressWithoutFunds, + transferAmount, + ); + done(); + })().catch(done); + }); + }); + describe('#getLogsAsync', () => { + let etherTokenAddress: string; + let tokenTransferProxyAddress: string; + const blockRange: BlockRange = { + fromBlock: 0, + toBlock: BlockParamLiteral.Latest, + }; + let txHash: string; + before(() => { + addressWithETH = userAddresses[0]; + const tokenUtils = new TokenUtils(tokens); + const etherToken = tokenUtils.getWethTokenOrThrow(); + etherTokenAddress = etherToken.address; + tokenTransferProxyAddress = zeroEx.proxy.getContractAddress(); + }); + it('should get logs with decoded args emitted by Approval', async () => { + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH); + await zeroEx.awaitTransactionMinedAsync(txHash); + const eventName = EtherTokenEvents.Approval; + const indexFilterValues = {}; + const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>( + etherTokenAddress, + eventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(1); + const args = logs[0].args; + expect(logs[0].event).to.be.equal(eventName); + expect(args._owner).to.be.equal(addressWithETH); + expect(args._spender).to.be.equal(tokenTransferProxyAddress); + expect(args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); + }); + it('should get logs with decoded args emitted by Deposit', async () => { + await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); + const eventName = EtherTokenEvents.Deposit; + const indexFilterValues = {}; + const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>( + etherTokenAddress, + eventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(1); + const args = logs[0].args; + expect(logs[0].event).to.be.equal(eventName); + expect(args._owner).to.be.equal(addressWithETH); + expect(args._value).to.be.bignumber.equal(depositAmount); + }); + it('should only get the logs with the correct event name', async () => { + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH); + await zeroEx.awaitTransactionMinedAsync(txHash); + const differentEventName = EtherTokenEvents.Transfer; + const indexFilterValues = {}; + const logs = await zeroEx.etherToken.getLogsAsync( + etherTokenAddress, + differentEventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(0); + }); + it('should only get the logs with the correct indexed fields', async () => { + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH); + await zeroEx.awaitTransactionMinedAsync(txHash); + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithoutFunds); + await zeroEx.awaitTransactionMinedAsync(txHash); + const eventName = EtherTokenEvents.Approval; + const indexFilterValues = { + _owner: addressWithETH, + }; + const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>( + etherTokenAddress, + eventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(1); + const args = logs[0].args; + expect(args._owner).to.be.equal(addressWithETH); + }); + }); }); diff --git a/packages/0x.js/test/event_watcher_test.ts b/packages/0x.js/test/event_watcher_test.ts index 3d92c62a3..f92fb2b02 100644 --- a/packages/0x.js/test/event_watcher_test.ts +++ b/packages/0x.js/test/event_watcher_test.ts @@ -1,22 +1,17 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import * as _ from 'lodash'; import 'mocha'; import * as Sinon from 'sinon'; import * as Web3 from 'web3'; -import { - DecodedLogEvent, - LogEvent, - ZeroEx, -} from '../src'; -import {EventWatcher} from '../src/order_watcher/event_watcher'; -import {DoneCallback} from '../src/types'; +import { LogEvent } from '../src'; +import { EventWatcher } from '../src/order_watcher/event_watcher'; +import { DoneCallback } from '../src/types'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { reportNodeCallbackErrors } from './utils/report_callback_errors'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; @@ -26,7 +21,6 @@ describe('EventWatcher', () => { let stubs: Sinon.SinonStub[] = []; let eventWatcher: EventWatcher; let web3Wrapper: Web3Wrapper; - const numConfirmations = 0; const logA: Web3.LogEntry = { address: '0x71d271f8b14adef568f8f28f1587ce7271ac4ca5', blockHash: null, @@ -43,7 +37,7 @@ describe('EventWatcher', () => { blockNumber: null, data: '', logIndex: null, - topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ], + topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'], transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25', transactionIndex: 0, }; @@ -53,7 +47,7 @@ describe('EventWatcher', () => { blockNumber: null, data: '', logIndex: null, - topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ], + topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'], transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25', transactionIndex: 0, }; @@ -84,13 +78,14 @@ describe('EventWatcher', () => { const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync'); getLogsStub.onCall(0).returns(logs); stubs.push(getLogsStub); - const callback = (event: LogEvent) => { + const expectedToBeCalledOnce = false; + const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => { const expectedLogEvent = expectedLogEvents.shift(); expect(event).to.be.deep.equal(expectedLogEvent); if (_.isEmpty(expectedLogEvents)) { done(); } - }; + }); eventWatcher.subscribe(callback); }); it('correctly computes the difference and emits only changes', (done: DoneCallback) => { @@ -118,13 +113,14 @@ describe('EventWatcher', () => { getLogsStub.onCall(0).returns(initialLogs); getLogsStub.onCall(1).returns(changedLogs); stubs.push(getLogsStub); - const callback = (event: LogEvent) => { + const expectedToBeCalledOnce = false; + const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => { const expectedLogEvent = expectedLogEvents.shift(); expect(event).to.be.deep.equal(expectedLogEvent); if (_.isEmpty(expectedLogEvents)) { done(); } - }; + }); eventWatcher.subscribe(callback); }); }); diff --git a/packages/0x.js/test/exchange_transfer_simulator_test.ts b/packages/0x.js/test/exchange_transfer_simulator_test.ts index a1d9bdade..20b4a05ca 100644 --- a/packages/0x.js/test/exchange_transfer_simulator_test.ts +++ b/packages/0x.js/test/exchange_transfer_simulator_test.ts @@ -1,18 +1,18 @@ -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; -import {ExchangeContractErrs, Token, ZeroEx} from '../src'; -import {BlockParamLiteral, TradeSide, TransferType} from '../src/types'; -import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator'; +import { ExchangeContractErrs, Token, ZeroEx } from '../src'; +import { BlockParamLiteral, TradeSide, TransferType } from '../src/types'; +import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); describe('ExchangeTransferSimulator', () => { const web3 = web3Factory.create(); @@ -45,17 +45,31 @@ describe('ExchangeTransferSimulator', () => { beforeEach(() => { exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest); }); - it('throws if the user doesn\'t have enough allowance', async () => { - return expect(exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade, - )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance); + it("throws if the user doesn't have enough allowance", async () => { + return expect( + exchangeTransferSimulator.transferFromAsync( + exampleTokenAddress, + sender, + recipient, + transferAmount, + TradeSide.Taker, + TransferType.Trade, + ), + ).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance); }); - it('throws if the user doesn\'t have enough balance', async () => { + it("throws if the user doesn't have enough balance", async () => { txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount); await zeroEx.awaitTransactionMinedAsync(txHash); - return expect(exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade, - )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); + return expect( + exchangeTransferSimulator.transferFromAsync( + exampleTokenAddress, + sender, + recipient, + transferAmount, + TradeSide.Maker, + TransferType.Trade, + ), + ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); }); it('updates balances and proxyAllowance after transfer', async () => { txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount); @@ -63,9 +77,14 @@ describe('ExchangeTransferSimulator', () => { txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount); await zeroEx.awaitTransactionMinedAsync(txHash); await exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade, + exampleTokenAddress, + sender, + recipient, + transferAmount, + TradeSide.Taker, + TransferType.Trade, ); - const store = (exchangeTransferSimulator as any).store; + const store = (exchangeTransferSimulator as any)._store; const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender); const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient); const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender); @@ -73,15 +92,20 @@ describe('ExchangeTransferSimulator', () => { expect(recipientBalance).to.be.bignumber.equal(transferAmount); expect(senderProxyAllowance).to.be.bignumber.equal(0); }); - it('doesn\'t update proxyAllowance after transfer if unlimited', async () => { + it("doesn't update proxyAllowance after transfer if unlimited", async () => { txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount); await zeroEx.awaitTransactionMinedAsync(txHash); txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender); await zeroEx.awaitTransactionMinedAsync(txHash); await exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade, + exampleTokenAddress, + sender, + recipient, + transferAmount, + TradeSide.Taker, + TransferType.Trade, ); - const store = (exchangeTransferSimulator as any).store; + const store = (exchangeTransferSimulator as any)._store; const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender); const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient); const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender); diff --git a/packages/0x.js/test/exchange_wrapper_test.ts b/packages/0x.js/test/exchange_wrapper_test.ts index 14559c706..7e0ffd818 100644 --- a/packages/0x.js/test/exchange_wrapper_test.ts +++ b/packages/0x.js/test/exchange_wrapper_test.ts @@ -1,34 +1,35 @@ -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; +import * as _ from 'lodash'; import 'mocha'; import * as Web3 from 'web3'; import { + BlockRange, DecodedLogEvent, ExchangeContractErrs, ExchangeEvents, LogCancelContractEventArgs, - LogEvent, LogFillContractEventArgs, OrderCancellationRequest, OrderFillRequest, SignedOrder, - SubscriptionOpts, Token, ZeroEx, } from '../src'; -import {BlockParamLiteral, DoneCallback} from '../src/types'; +import { BlockParamLiteral, DoneCallback } from '../src/types'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {FillScenarios} from './utils/fill_scenarios'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { FillScenarios } from './utils/fill_scenarios'; +import { reportNodeCallbackErrors } from './utils/report_callback_errors'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); const NON_EXISTENT_ORDER_HASH = '0x79370342234e7acd6bbeac335bd3bb1d368383294b64b8160a00f4060e4d3777'; @@ -53,6 +54,7 @@ describe('ExchangeWrapper', () => { tokenUtils = new TokenUtils(tokens); zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); + await fillScenarios.initTokenBalancesAsync(); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -71,7 +73,7 @@ describe('ExchangeWrapper', () => { before(async () => { [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; tokens = await zeroEx.tokenRegistry.getTokensAsync(); - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); @@ -80,10 +82,18 @@ describe('ExchangeWrapper', () => { const fillableAmount = new BigNumber(5); const partialFillTakerAmount = new BigNumber(2); const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const orderFillRequests = [ { @@ -103,7 +113,11 @@ describe('ExchangeWrapper', () => { const fillableAmount = new BigNumber(5); beforeEach(async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); orderFillRequests = [ { @@ -113,18 +127,23 @@ describe('ExchangeWrapper', () => { ]; }); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress)) - .to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { + shouldValidate: true, + }), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { + shouldValidate: false, + }), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); }); }); @@ -133,57 +152,78 @@ describe('ExchangeWrapper', () => { const fillableAmount = new BigNumber(5); beforeEach(async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); }); describe('successful fills', () => { it('should fill a valid order', async () => { - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) - .to.be.bignumber.equal(fillableAmount); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) - .to.be.bignumber.equal(0); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) - .to.be.bignumber.equal(0); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillableAmount); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal( + fillableAmount, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal( + 0, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal( + 0, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal( + fillableAmount, + ); await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) - .to.be.bignumber.equal(takerTokenFillAmount); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) - .to.be.bignumber.equal(takerTokenFillAmount); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal( + fillableAmount.minus(takerTokenFillAmount), + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal( + takerTokenFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal( + takerTokenFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal( + fillableAmount.minus(takerTokenFillAmount), + ); }); it('should partially fill a valid order', async () => { const partialFillAmount = new BigNumber(3); await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) - .to.be.bignumber.equal(partialFillAmount); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) - .to.be.bignumber.equal(partialFillAmount); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal( + fillableAmount.minus(partialFillAmount), + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal( + partialFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal( + partialFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal( + fillableAmount.minus(partialFillAmount), + ); }); }); describe('order transaction options', () => { const emptyFillableAmount = new BigNumber(0); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress)) - .to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { + shouldValidate: true, + }), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { + shouldValidate: false, + }), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); }); }); @@ -201,7 +241,7 @@ describe('ExchangeWrapper', () => { before(async () => { [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; tokens = await zeroEx.tokenRegistry.getTokensAsync(); - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); @@ -209,57 +249,96 @@ describe('ExchangeWrapper', () => { describe('successful fills', () => { it('should fill a valid order', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, - ); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) - .to.be.bignumber.equal(fillableAmount); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) - .to.be.bignumber.equal(0); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) - .to.be.bignumber.equal(0); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillableAmount); + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal( + fillableAmount, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal( + 0, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal( + 0, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal( + fillableAmount, + ); const txHash = await zeroEx.exchange.fillOrderAsync( - signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); + signedOrder, + takerTokenFillAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ); await zeroEx.awaitTransactionMinedAsync(txHash); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) - .to.be.bignumber.equal(takerTokenFillAmount); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) - .to.be.bignumber.equal(takerTokenFillAmount); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal( + fillableAmount.minus(takerTokenFillAmount), + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal( + takerTokenFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal( + takerTokenFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal( + fillableAmount.minus(takerTokenFillAmount), + ); }); it('should partially fill the valid order', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const partialFillAmount = new BigNumber(3); const txHash = await zeroEx.exchange.fillOrderAsync( - signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); + signedOrder, + partialFillAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ); await zeroEx.awaitTransactionMinedAsync(txHash); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) - .to.be.bignumber.equal(partialFillAmount); - expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) - .to.be.bignumber.equal(partialFillAmount); - expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal( + fillableAmount.minus(partialFillAmount), + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal( + partialFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal( + partialFillAmount, + ); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal( + fillableAmount.minus(partialFillAmount), + ); }); it('should fill the valid orders with fees', async () => { const makerFee = new BigNumber(1); const takerFee = new BigNumber(2); const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, takerTokenAddress, makerFee, takerFee, - makerAddress, takerAddress, fillableAmount, feeRecipient, + makerTokenAddress, + takerTokenAddress, + makerFee, + takerFee, + makerAddress, + takerAddress, + fillableAmount, + feeRecipient, ); const txHash = await zeroEx.exchange.fillOrderAsync( - signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); + signedOrder, + takerTokenFillAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ); await zeroEx.awaitTransactionMinedAsync(txHash); - expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)) - .to.be.bignumber.equal(makerFee.plus(takerFee)); + expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)).to.be.bignumber.equal( + makerFee.plus(takerFee), + ); }); }); describe('order transaction options', () => { @@ -267,25 +346,71 @@ describe('ExchangeWrapper', () => { const emptyFillTakerAmount = new BigNumber(0); beforeEach(async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); }); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.fillOrderAsync( - signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrderAsync( + signedOrder, + emptyFillTakerAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.fillOrderAsync( - signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrderAsync( + signedOrder, + emptyFillTakerAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + { + shouldValidate: true, + }, + ), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.fillOrderAsync( - signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrderAsync( + signedOrder, + emptyFillTakerAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + { + shouldValidate: false, + }, + ), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + }); + }); + describe('negative fill amount', async () => { + let signedOrder: SignedOrder; + const negativeFillTakerAmount = new BigNumber(-100); + beforeEach(async () => { + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + ); + }); + it('should not allow the exchange wrapper to fill if amount is negative', async () => { + return expect( + zeroEx.exchange.fillOrderAsync( + signedOrder, + negativeFillTakerAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), + ).to.be.rejected(); }); }); }); @@ -297,11 +422,19 @@ describe('ExchangeWrapper', () => { let orderFillBatch: OrderFillRequest[]; beforeEach(async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder); anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder); }); @@ -319,13 +452,20 @@ describe('ExchangeWrapper', () => { ]; }); it('should throw if a batch is empty', async () => { - return expect(zeroEx.exchange.batchFillOrdersAsync( - [], shouldThrowOnInsufficientBalanceOrAllowance, takerAddress), + return expect( + zeroEx.exchange.batchFillOrdersAsync( + [], + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); }); it('should successfully fill multiple orders', async () => { const txHash = await zeroEx.exchange.batchFillOrdersAsync( - orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); + orderFillBatch, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ); await zeroEx.awaitTransactionMinedAsync(txHash); const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex); const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex); @@ -348,21 +488,61 @@ describe('ExchangeWrapper', () => { ]; }); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.batchFillOrdersAsync( - orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress), + return expect( + zeroEx.exchange.batchFillOrdersAsync( + orderFillBatch, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.batchFillOrdersAsync( - orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.batchFillOrdersAsync( + orderFillBatch, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + { + shouldValidate: true, + }, + ), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.batchFillOrdersAsync( - orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.batchFillOrdersAsync( + orderFillBatch, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + { + shouldValidate: false, + }, + ), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + }); + }); + describe('negative batch fill amount', async () => { + beforeEach(async () => { + const negativeFillTakerAmount = new BigNumber(-100); + orderFillBatch = [ + { + signedOrder, + takerTokenFillAmount, + }, + { + signedOrder: anotherSignedOrder, + takerTokenFillAmount: negativeFillTakerAmount, + }, + ]; + }); + it('should not allow the exchange wrapper to batch fill if any amount is negative', async () => { + return expect( + zeroEx.exchange.batchFillOrdersAsync( + orderFillBatch, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), + ).to.be.rejected(); }); }); }); @@ -375,24 +555,57 @@ describe('ExchangeWrapper', () => { const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1); beforeEach(async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder); anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder); signedOrders = [signedOrder, anotherSignedOrder]; }); describe('successful batch fills', () => { it('should throw if a batch is empty', async () => { - return expect(zeroEx.exchange.fillOrdersUpToAsync( - [], fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress), + return expect( + zeroEx.exchange.fillOrdersUpToAsync( + [], + fillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); }); - it('should successfully fill up to specified amount', async () => { + it('should successfully fill up to specified amount when all orders are fully funded', async () => { + const txHash = await zeroEx.exchange.fillOrdersUpToAsync( + signedOrders, + fillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ); + await zeroEx.awaitTransactionMinedAsync(txHash); + const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex); + const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex); + expect(filledAmount).to.be.bignumber.equal(fillableAmount); + const remainingFillAmount = fillableAmount.minus(1); + expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount); + }); + it('should successfully fill up to specified amount even if filling all orders would fail', async () => { + const missingBalance = new BigNumber(1); // User will still have enough balance to fill up to 9, + // but won't have 10 to fully fill all orders in a batch. + await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance); const txHash = await zeroEx.exchange.fillOrdersUpToAsync( - signedOrders, fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + signedOrders, + fillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, ); await zeroEx.awaitTransactionMinedAsync(txHash); const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex); @@ -402,24 +615,57 @@ describe('ExchangeWrapper', () => { expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount); }); }); + describe('failed batch fills', () => { + it("should fail validation if user doesn't have enough balance without fill up to", async () => { + const missingBalance = new BigNumber(2); // User will only have enough balance to fill up to 8 + await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance); + return expect( + zeroEx.exchange.fillOrdersUpToAsync( + signedOrders, + fillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), + ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); + }); + }); describe('order transaction options', () => { const emptyFillUpToAmount = new BigNumber(0); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.fillOrdersUpToAsync( - signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrdersUpToAsync( + signedOrders, + emptyFillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + ), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.fillOrdersUpToAsync( - signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrdersUpToAsync( + signedOrders, + emptyFillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + { + shouldValidate: true, + }, + ), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.fillOrdersUpToAsync( - signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.fillOrdersUpToAsync( + signedOrders, + emptyFillUpToAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, + { + shouldValidate: false, + }, + ), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); }); }); @@ -436,11 +682,15 @@ describe('ExchangeWrapper', () => { const cancelAmount = new BigNumber(3); beforeEach(async () => { [coinbase, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); orderHashHex = ZeroEx.getOrderHashHex(signedOrder); }); @@ -456,18 +706,23 @@ describe('ExchangeWrapper', () => { describe('order transaction options', () => { const emptyCancelTakerTokenAmount = new BigNumber(0); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount)) - .to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect( + zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount), + ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect( + zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { + shouldValidate: true, + }), + ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect( + zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { + shouldValidate: false, + }), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }); }); }); @@ -477,7 +732,11 @@ describe('ExchangeWrapper', () => { let cancelBatch: OrderCancellationRequest[]; beforeEach(async () => { anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder); cancelBatch = [ @@ -494,15 +753,21 @@ describe('ExchangeWrapper', () => { describe('failed batch cancels', () => { it('should throw when orders have different makers', async () => { const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + takerAddress, + takerAddress, + fillableAmount, ); - return expect(zeroEx.exchange.batchCancelOrdersAsync([ - cancelBatch[0], - { - order: signedOrderWithDifferentMaker, - takerTokenCancelAmount: cancelAmount, - }, - ])).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); + return expect( + zeroEx.exchange.batchCancelOrdersAsync([ + cancelBatch[0], + { + order: signedOrderWithDifferentMaker, + takerTokenCancelAmount: cancelAmount, + }, + ]), + ).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); }); }); describe('successful batch cancels', () => { @@ -531,18 +796,23 @@ describe('ExchangeWrapper', () => { ]; }); it('should validate when orderTransactionOptions are not present', async () => { - return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)) - .to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)).to.be.rejectedWith( + ExchangeContractErrs.OrderCancelAmountZero, + ); }); it('should validate when orderTransactionOptions specify to validate', async () => { - return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, { - shouldValidate: true, - })).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect( + zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, { + shouldValidate: true, + }), + ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }); it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, { - shouldValidate: false, - })).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect( + zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, { + shouldValidate: false, + }), + ).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }); }); }); @@ -557,7 +827,8 @@ describe('ExchangeWrapper', () => { let orderHash: string; before(() => { takerAddress = userAddresses[1]; - const [makerToken, takerToken] = tokens; + tokenUtils = new TokenUtils(tokens); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); @@ -565,7 +836,11 @@ describe('ExchangeWrapper', () => { fillableAmount = new BigNumber(5); partialFillAmount = new BigNumber(2); signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, partialFillAmount, + makerTokenAddress, + takerTokenAddress, + takerAddress, + fillableAmount, + partialFillAmount, ); orderHash = ZeroEx.getOrderHashHex(signedOrder); }); @@ -589,8 +864,7 @@ describe('ExchangeWrapper', () => { return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected(); }); it('should return zero if passed a valid but non-existent orderHash', async () => { - const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH, - ); + const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH); expect(filledValueT).to.be.bignumber.equal(0); }); it('should return the filledValueT for a valid and partially filled orderHash', async () => { @@ -633,14 +907,18 @@ describe('ExchangeWrapper', () => { const cancelTakerAmountInBaseUnits = new BigNumber(1); before(() => { [coinbase, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokens; + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); beforeEach(async () => { fillableAmount = new BigNumber(5); signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); }); afterEach(async () => { @@ -653,70 +931,74 @@ describe('ExchangeWrapper', () => { // Source: https://github.com/mochajs/mocha/issues/2407 it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => { (async () => { - - const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); - done(); - }; - zeroEx.exchange.subscribe( - ExchangeEvents.LogFill, indexFilterValues, callback, + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { + expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); + }, ); + zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback); await zeroEx.exchange.fillOrderAsync( - signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, + signedOrder, + takerTokenFillAmountInBaseUnits, + shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); })().catch(done); }); it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => { (async () => { - - const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => { - expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel); - done(); - }; - zeroEx.exchange.subscribe( - ExchangeEvents.LogCancel, indexFilterValues, callback, + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => { + expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel); + }, ); + zeroEx.exchange.subscribe(ExchangeEvents.LogCancel, indexFilterValues, callback); await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits); })().catch(done); }); it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => { (async () => { - - const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - done(new Error('Expected this subscription to have been cancelled')); - }; - zeroEx.exchange.subscribe( - ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled, + const callbackNeverToBeCalled = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, ); + zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled); const newProvider = web3Factory.getRpcProvider(); zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID); - const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); - done(); - }; - zeroEx.exchange.subscribe( - ExchangeEvents.LogFill, indexFilterValues, callback, + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { + expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); + }, ); + zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback); await zeroEx.exchange.fillOrderAsync( - signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, + signedOrder, + takerTokenFillAmountInBaseUnits, + shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); })().catch(done); }); it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { (async () => { - const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - done(new Error('Expected this subscription to have been cancelled')); - }; + const callbackNeverToBeCalled = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, + ); const subscriptionToken = zeroEx.exchange.subscribe( - ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled, + ExchangeEvents.LogFill, + indexFilterValues, + callbackNeverToBeCalled, ); zeroEx.exchange.unsubscribe(subscriptionToken); await zeroEx.exchange.fillOrderAsync( - signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, + signedOrder, + takerTokenFillAmountInBaseUnits, + shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); done(); @@ -731,17 +1013,22 @@ describe('ExchangeWrapper', () => { const fillableAmount = new BigNumber(5); before(async () => { [, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); - it('get\'s the same hash as the local function', async () => { + it("get's the same hash as the local function", async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); - const orderHashFromContract = await (zeroEx.exchange as any) - ._getOrderHashHexUsingContractCallAsync(signedOrder); + const orderHashFromContract = await (zeroEx.exchange as any)._getOrderHashHexUsingContractCallAsync( + signedOrder, + ); expect(orderHash).to.equal(orderHashFromContract); }); }); @@ -759,59 +1046,87 @@ describe('ExchangeWrapper', () => { let takerAddress: string; const fillableAmount = new BigNumber(5); const shouldThrowOnInsufficientBalanceOrAllowance = true; - const subscriptionOpts: SubscriptionOpts = { + const blockRange: BlockRange = { fromBlock: 0, toBlock: BlockParamLiteral.Latest, }; let txHash: string; before(async () => { [, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); it('should get logs with decoded args emitted by LogFill', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); txHash = await zeroEx.exchange.fillOrderAsync( - signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + signedOrder, + fillableAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, ); await zeroEx.awaitTransactionMinedAsync(txHash); const eventName = ExchangeEvents.LogFill; const indexFilterValues = {}; - const logs = await zeroEx.exchange.getLogsAsync(eventName, subscriptionOpts, indexFilterValues); + const logs = await zeroEx.exchange.getLogsAsync(eventName, blockRange, indexFilterValues); expect(logs).to.have.length(1); expect(logs[0].event).to.be.equal(eventName); }); it('should only get the logs with the correct event name', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); txHash = await zeroEx.exchange.fillOrderAsync( - signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + signedOrder, + fillableAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, ); await zeroEx.awaitTransactionMinedAsync(txHash); const differentEventName = ExchangeEvents.LogCancel; const indexFilterValues = {}; - const logs = await zeroEx.exchange.getLogsAsync(differentEventName, subscriptionOpts, indexFilterValues); + const logs = await zeroEx.exchange.getLogsAsync(differentEventName, blockRange, indexFilterValues); expect(logs).to.have.length(0); }); it('should only get the logs with the correct indexed fields', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); txHash = await zeroEx.exchange.fillOrderAsync( - signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + signedOrder, + fillableAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, ); await zeroEx.awaitTransactionMinedAsync(txHash); const differentMakerAddress = userAddresses[2]; const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, differentMakerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + differentMakerAddress, + takerAddress, + fillableAmount, ); txHash = await zeroEx.exchange.fillOrderAsync( - anotherSignedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + anotherSignedOrder, + fillableAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, ); await zeroEx.awaitTransactionMinedAsync(txHash); @@ -820,7 +1135,9 @@ describe('ExchangeWrapper', () => { maker: differentMakerAddress, }; const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>( - eventName, subscriptionOpts, indexFilterValues, + eventName, + blockRange, + indexFilterValues, ); expect(logs).to.have.length(1); const args = logs[0].args; diff --git a/packages/0x.js/test/expiration_watcher_test.ts b/packages/0x.js/test/expiration_watcher_test.ts index d4581259d..770615f88 100644 --- a/packages/0x.js/test/expiration_watcher_test.ts +++ b/packages/0x.js/test/expiration_watcher_test.ts @@ -1,27 +1,27 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; import 'mocha'; import * as Sinon from 'sinon'; import * as Web3 from 'web3'; -import {ZeroEx} from '../src/0x'; -import {ExpirationWatcher} from '../src/order_watcher/expiration_watcher'; -import {DoneCallback, Token} from '../src/types'; -import {constants} from '../src/utils/constants'; -import {utils} from '../src/utils/utils'; +import { ZeroEx } from '../src/0x'; +import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher'; +import { DoneCallback, Token } from '../src/types'; +import { constants } from '../src/utils/constants'; +import { utils } from '../src/utils/utils'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {FillScenarios} from './utils/fill_scenarios'; -import {reportCallbackErrors} from './utils/report_callback_errors'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants as testConstants } from './utils/constants'; +import { FillScenarios } from './utils/fill_scenarios'; +import { reportNoErrorCallbackErrors } from './utils/report_callback_errors'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(testConstants.RPC_URL); describe('ExpirationWatcher', () => { let web3: Web3; @@ -56,13 +56,13 @@ describe('ExpirationWatcher', () => { fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; tokens = await zeroEx.tokenRegistry.getTokensAsync(); - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; }); beforeEach(async () => { await blockchainLifecycle.startAsync(); - const sinonTimerConfig = {shouldAdvanceTime: true} as any; + const sinonTimerConfig = { shouldAdvanceTime: true } as any; // This constructor has incorrect types timer = Sinon.useFakeTimers(sinonTimerConfig); currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); @@ -78,31 +78,38 @@ describe('ExpirationWatcher', () => { const orderLifetimeSec = 60; const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec); const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, expirationUnixTimestampSec, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000)); - const callbackAsync = reportCallbackErrors(done)(async (hash: string) => { + const callbackAsync = reportNoErrorCallbackErrors(done)((hash: string) => { expect(hash).to.be.equal(orderHash); expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec); - done(); }); expirationWatcher.subscribe(callbackAsync); timer.tick(orderLifetimeSec * 1000); })().catch(done); }); - it('doesn\'t emit events before order expires', (done: DoneCallback) => { + it("doesn't emit events before order expires", (done: DoneCallback) => { (async () => { const orderLifetimeSec = 60; const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec); const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, expirationUnixTimestampSec, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000)); - const callbackAsync = reportCallbackErrors(done)(async (hash: string) => { + const callbackAsync = reportNoErrorCallbackErrors(done)(async (hash: string) => { done(new Error('Emitted expiration went before the order actually expired')); }); expirationWatcher.subscribe(callbackAsync); @@ -118,11 +125,19 @@ describe('ExpirationWatcher', () => { const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime); const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime); const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, order1ExpirationUnixTimestampSec, ); const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, order2ExpirationUnixTimestampSec, ); const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1); @@ -130,7 +145,8 @@ describe('ExpirationWatcher', () => { expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000)); expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000)); const expirationOrder = [orderHash1, orderHash2]; - const callbackAsync = reportCallbackErrors(done)(async (hash: string) => { + const expectToBeCalledOnce = false; + const callbackAsync = reportNoErrorCallbackErrors(done, expectToBeCalledOnce)((hash: string) => { const orderHash = expirationOrder.shift(); expect(hash).to.be.equal(orderHash); if (_.isEmpty(expirationOrder)) { diff --git a/packages/0x.js/test/order_state_watcher_test.ts b/packages/0x.js/test/order_state_watcher_test.ts index b5968dc24..2e9202fe2 100644 --- a/packages/0x.js/test/order_state_watcher_test.ts +++ b/packages/0x.js/test/order_state_watcher_test.ts @@ -1,39 +1,34 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; import 'mocha'; import * as Web3 from 'web3'; import { - DecodedLogEvent, ExchangeContractErrs, - LogEvent, OrderState, OrderStateInvalid, OrderStateValid, SignedOrder, Token, ZeroEx, - ZeroExConfig, ZeroExError, } from '../src'; -import {OrderStateWatcher} from '../src/order_watcher/order_state_watcher'; -import {DoneCallback} from '../src/types'; +import { DoneCallback } from '../src/types'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {FillScenarios} from './utils/fill_scenarios'; -import {reportCallbackErrors} from './utils/report_callback_errors'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { FillScenarios } from './utils/fill_scenarios'; +import { reportNodeCallbackErrors } from './utils/report_callback_errors'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; const TIMEOUT_MS = 150; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); describe('OrderStateWatcher', () => { let web3: Web3; @@ -48,7 +43,6 @@ describe('OrderStateWatcher', () => { let takerToken: Token; let maker: string; let taker: string; - let web3Wrapper: Web3Wrapper; let signedOrder: SignedOrder; const config = { networkId: constants.TESTRPC_NETWORK_ID, @@ -65,8 +59,8 @@ describe('OrderStateWatcher', () => { tokenUtils = new TokenUtils(tokens); zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); - [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); - web3Wrapper = (zeroEx as any)._web3Wrapper; + await fillScenarios.initTokenBalancesAsync(); + [makerToken, takerToken] = tokenUtils.getDummyTokens(); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -77,7 +71,11 @@ describe('OrderStateWatcher', () => { describe('#removeOrder', async () => { it('should successfully remove existing order', async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); @@ -95,10 +93,18 @@ describe('OrderStateWatcher', () => { }); it('should no-op when removing a non-existing order', async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); - const nonExistentOrderHash = `0x${orderHash.substr(2).split('').reverse().join('')}`; + const nonExistentOrderHash = `0x${orderHash + .substr(2) + .split('') + .reverse() + .join('')}`; zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash); }); }); @@ -108,8 +114,7 @@ describe('OrderStateWatcher', () => { }); it('should fail when trying to subscribe twice', async () => { zeroEx.orderStateWatcher.subscribe(_.noop); - expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)) - .to.throw(ZeroExError.SubscriptionAlreadyPresent); + expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)).to.throw(ZeroExError.SubscriptionAlreadyPresent); }); }); describe('tests with cleanup', async () => { @@ -121,16 +126,19 @@ describe('OrderStateWatcher', () => { it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0)); @@ -139,18 +147,20 @@ describe('OrderStateWatcher', () => { it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); - const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { throw new Error('OrderState callback fired for irrelevant order'); }); zeroEx.orderStateWatcher.subscribe(callback); const notTheMaker = userAddresses[0]; const anyRecipient = taker; const transferAmount = new BigNumber(2); - const notTheMakerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, notTheMaker); await zeroEx.token.transferAsync(makerToken.address, notTheMaker, anyRecipient, transferAmount); setTimeout(() => { done(); @@ -160,16 +170,19 @@ describe('OrderStateWatcher', () => { it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); const anyRecipient = taker; @@ -180,40 +193,48 @@ describe('OrderStateWatcher', () => { it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); const shouldThrowOnInsufficientBalanceOrAllowance = true; await zeroEx.exchange.fillOrderAsync( - signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker, + signedOrder, + fillableAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + taker, ); })().catch(done); }); it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); - const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker); - const fillAmountInBaseUnits = new BigNumber(2); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); const validOrderState = orderState as OrderStateValid; expect(validOrderState.orderHash).to.be.equal(orderHash); @@ -221,16 +242,20 @@ describe('OrderStateWatcher', () => { const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits); const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits); expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - remainingFillable); + remainingFillable, + ); expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( - remainingFillable); + remainingFillable, + ); expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); const shouldThrowOnInsufficientBalanceOrAllowance = true; await zeroEx.exchange.fillOrderAsync( - signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker, + signedOrder, + fillAmountInBaseUnits, + shouldThrowOnInsufficientBalanceOrAllowance, + taker, ); })().catch(done); }); @@ -239,13 +264,17 @@ describe('OrderStateWatcher', () => { const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18); const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18); signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount, - taker); - const orderHash = ZeroEx.getOrderHashHex(signedOrder); + makerToken.address, + takerToken.address, + makerFee, + takerFee, + maker, + taker, + fillableAmount, + taker, + ); + const callback = reportNodeCallbackErrors(done)(); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { - done(); - }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, new BigNumber(0)); })().catch(done); @@ -256,51 +285,60 @@ describe('OrderStateWatcher', () => { const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals); const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals); signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, makerFillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + makerFillableAmount, takerFillableAmount, ); - const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); - const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker); const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); const validOrderState = orderState as OrderStateValid; expect(validOrderState.orderHash).to.be.equal(orderHash); const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals)); + ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals), + ); expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( - ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals)); - done(); + ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals), + ); }); zeroEx.orderStateWatcher.subscribe(callback); const shouldThrowOnInsufficientBalanceOrAllowance = true; await zeroEx.exchange.fillOrderAsync( - signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker, + signedOrder, + fillAmountInBaseUnits, + shouldThrowOnInsufficientBalanceOrAllowance, + taker, ); })().catch(done); }); it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); - const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); - const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { const validOrderState = orderState as OrderStateValid; const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - changedMakerApprovalAmount); + changedMakerApprovalAmount, + ); expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( - changedMakerApprovalAmount); - done(); + changedMakerApprovalAmount, + ); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount); @@ -309,7 +347,11 @@ describe('OrderStateWatcher', () => { it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); @@ -318,19 +360,19 @@ describe('OrderStateWatcher', () => { const transferAmount = makerBalance.sub(remainingAmount); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); const validOrderState = orderState as OrderStateValid; const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - remainingAmount); + remainingAmount, + ); expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( - remainingAmount); - done(); + remainingAmount, + ); }); zeroEx.orderStateWatcher.subscribe(callback); - await zeroEx.token.transferAsync( - makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount); + await zeroEx.token.transferAsync(makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount); })().catch(done); }); it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => { @@ -339,22 +381,27 @@ describe('OrderStateWatcher', () => { const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals); const feeRecipient = taker; signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerToken.address, takerToken.address, makerFee, takerFee, maker, - taker, fillableAmount, feeRecipient); - - const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); + makerToken.address, + takerToken.address, + makerFee, + takerFee, + maker, + taker, + fillableAmount, + feeRecipient, + ); const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals); const transferTokenAmount = makerFee.sub(remainingTokenAmount); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); const validOrderState = orderState as OrderStateValid; const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - remainingTokenAmount); - done(); + remainingTokenAmount, + ); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.exchange.cancelOrderAsync(signedOrder, transferTokenAmount); @@ -366,29 +413,37 @@ describe('OrderStateWatcher', () => { const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals); const feeRecipient = taker; signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerToken.address, takerToken.address, makerFee, takerFee, maker, - taker, fillableAmount, feeRecipient); - - const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); + makerToken.address, + takerToken.address, + makerFee, + takerFee, + maker, + taker, + fillableAmount, + feeRecipient, + ); const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals); - const transferFeeAmount = makerFee.sub(remainingFeeAmount); const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals); const transferTokenAmount = makerFee.sub(remainingTokenAmount); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { const validOrderState = orderState as OrderStateValid; const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - remainingFeeAmount); - done(); + remainingFeeAmount, + ); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount); await zeroEx.token.transferAsync( - makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferTokenAmount); + makerToken.address, + maker, + ZeroEx.NULL_ADDRESS, + transferTokenAmount, + ); })().catch(done); }); it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => { @@ -397,43 +452,54 @@ describe('OrderStateWatcher', () => { const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const feeRecipient = taker; signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerToken.address, takerToken.address, makerFee, takerFee, maker, - taker, fillableAmount, feeRecipient); + makerToken.address, + takerToken.address, + makerFee, + takerFee, + maker, + taker, + fillableAmount, + feeRecipient, + ); - const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { const validOrderState = orderState as OrderStateValid; const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( - fillableAmount); - done(); + fillableAmount, + ); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.token.setProxyAllowanceAsync( - makerToken.address, maker, ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals)); + makerToken.address, + maker, + ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals), + ); })().catch(done); }); }); it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); - const shouldThrowOnInsufficientBalanceOrAllowance = true; await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); })().catch(done); }); @@ -441,44 +507,48 @@ describe('OrderStateWatcher', () => { (async () => { const remainingFillableAmountInBaseUnits = new BigNumber(100); signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.exchange.cancelOrderAsync( - signedOrder, fillableAmount.minus(remainingFillableAmountInBaseUnits), + signedOrder, + fillableAmount.minus(remainingFillableAmountInBaseUnits), ); })().catch(done); }); it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => { (async () => { signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, takerToken.address, maker, taker, fillableAmount, + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, ); - const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); - const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker); - const cancelAmountInBaseUnits = new BigNumber(2); const orderHash = ZeroEx.getOrderHashHex(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder); - const callback = reportCallbackErrors(done)((orderState: OrderState) => { + const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); const validOrderState = orderState as OrderStateValid; expect(validOrderState.orderHash).to.be.equal(orderHash); const orderRelevantState = validOrderState.orderRelevantState; expect(orderRelevantState.cancelledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits); - done(); }); zeroEx.orderStateWatcher.subscribe(callback); await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits); diff --git a/packages/0x.js/test/order_validation_test.ts b/packages/0x.js/test/order_validation_test.ts index d585c1f3c..be3e0590c 100644 --- a/packages/0x.js/test/order_validation_test.ts +++ b/packages/0x.js/test/order_validation_test.ts @@ -1,23 +1,23 @@ -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as Sinon from 'sinon'; import * as Web3 from 'web3'; -import {ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError} from '../src'; -import {BlockParamLiteral, TradeSide, TransferType} from '../src/types'; -import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator'; -import {OrderValidationUtils} from '../src/utils/order_validation_utils'; +import { ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError } from '../src'; +import { BlockParamLiteral, TradeSide, TransferType } from '../src/types'; +import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; +import { OrderValidationUtils } from '../src/utils/order_validation_utils'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {FillScenarios} from './utils/fill_scenarios'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { FillScenarios } from './utils/fill_scenarios'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); describe('OrderValidation', () => { let web3: Web3; @@ -34,7 +34,6 @@ describe('OrderValidation', () => { let makerAddress: string; let takerAddress: string; let feeRecipient: string; - let orderValidationUtils: OrderValidationUtils; const fillableAmount = new BigNumber(5); const fillTakerAmount = new BigNumber(5); const config = { @@ -50,10 +49,9 @@ describe('OrderValidation', () => { tokenUtils = new TokenUtils(tokens); zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; - orderValidationUtils = new OrderValidationUtils(zeroEx.token, zeroEx.exchange); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -64,108 +62,152 @@ describe('OrderValidation', () => { describe('validateOrderFillableOrThrowAsync', () => { it('should succeed if the order is fillable', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, - ); - await zeroEx.exchange.validateOrderFillableOrThrowAsync( - signedOrder, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); + await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder); }); it('should succeed if the order is asymmetric and fillable', async () => { const makerFillableAmount = fillableAmount; const takerFillableAmount = fillableAmount.minus(4); const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - makerFillableAmount, takerFillableAmount, - ); - await zeroEx.exchange.validateOrderFillableOrThrowAsync( - signedOrder, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + makerFillableAmount, + takerFillableAmount, ); + await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder); }); it('should throw when the order is fully filled or cancelled', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); - return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync( - signedOrder, - )).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero); + return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith( + ExchangeContractErrs.OrderRemainingFillAmountZero, + ); }); it('should throw when order is expired', async () => { const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - fillableAmount, expirationInPast, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + expirationInPast, + ); + return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith( + ExchangeContractErrs.OrderFillExpired, ); - return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync( - signedOrder, - )).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired); }); }); describe('validateFillOrderAndThrowIfInvalidAsync', () => { it('should throw when the fill amount is zero', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const zeroFillAmount = new BigNumber(0); - return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, zeroFillAmount, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); + return expect( + zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, zeroFillAmount, takerAddress), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }); it('should throw when the signature is invalid', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); // 27 <--> 28 - signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27; - return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillableAmount, takerAddress, - )).to.be.rejectedWith(ZeroExError.InvalidSignature); + signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27; + return expect( + zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress), + ).to.be.rejectedWith(ZeroExError.InvalidSignature); }); it('should throw when the order is fully filled or cancelled', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); - return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillableAmount, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero); + return expect( + zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress), + ).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero); }); it('should throw when sender is not a taker', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const nonTakerAddress = userAddresses[6]; - return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillTakerAmount, nonTakerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); + return expect( + zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, nonTakerAddress), + ).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); }); it('should throw when order is expired', async () => { const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - fillableAmount, expirationInPast, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + expirationInPast, ); - return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillTakerAmount, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired); + return expect( + zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired); }); it('should throw when there a rounding error would have occurred', async () => { const makerAmount = new BigNumber(3); const takerAmount = new BigNumber(5); const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - makerAmount, takerAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + makerAmount, + takerAmount, ); const fillTakerAmountThatCausesRoundingError = new BigNumber(3); - return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillTakerAmountThatCausesRoundingError, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError); + return expect( + zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( + signedOrder, + fillTakerAmountThatCausesRoundingError, + takerAddress, + ), + ).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError); }); }); describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => { it('should throw if remaining fillAmount is less then the desired fillAmount', async () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); const tooLargeFillAmount = new BigNumber(7); const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount); @@ -174,44 +216,56 @@ describe('OrderValidation', () => { await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference); await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount); - return expect(zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync( - signedOrder, tooLargeFillAmount, takerAddress, - )).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount); + return expect( + zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync( + signedOrder, + tooLargeFillAmount, + takerAddress, + ), + ).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount); }); }); describe('validateCancelOrderAndThrowIfInvalidAsync', () => { let signedOrder: SignedOrder; - let orderHashHex: string; const cancelAmount = new BigNumber(3); beforeEach(async () => { [coinbase, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + const [makerToken, takerToken] = tokenUtils.getDummyTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, ); - orderHashHex = ZeroEx.getOrderHashHex(signedOrder); }); it('should throw when cancel amount is zero', async () => { const zeroCancelAmount = new BigNumber(0); - return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount)) - .to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); + return expect( + zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount), + ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }); it('should throw when order is expired', async () => { const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - fillableAmount, expirationInPast, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + expirationInPast, ); - orderHashHex = ZeroEx.getOrderHashHex(expiredSignedOrder); - return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount)) - .to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired); + return expect( + zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount), + ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired); }); it('should throw when order is already cancelled or filled', async () => { await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); - return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount)) - .to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); + return expect( + zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount), + ).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); }); }); describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => { @@ -229,82 +283,159 @@ describe('OrderValidation', () => { const makerFee = new BigNumber(2); const takerFee = new BigNumber(2); const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, takerTokenAddress, makerFee, takerFee, - makerAddress, takerAddress, fillableAmount, feeRecipient, + makerTokenAddress, + takerTokenAddress, + makerFee, + takerFee, + makerAddress, + takerAddress, + fillableAmount, + feeRecipient, ); await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress, + exchangeTransferSimulator, + signedOrder, + fillableAmount, + takerAddress, + zrxTokenAddress, ); expect(transferFromAsync.callCount).to.be.equal(4); expect( - transferFromAsync.getCall(0).calledWith( - makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount), - TradeSide.Maker, TransferType.Trade, - ), + transferFromAsync + .getCall(0) + .calledWith( + makerTokenAddress, + makerAddress, + takerAddress, + bigNumberMatch(fillableAmount), + TradeSide.Maker, + TransferType.Trade, + ), ).to.be.true(); expect( - transferFromAsync.getCall(1).calledWith( - takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount), - TradeSide.Taker, TransferType.Trade, - ), + transferFromAsync + .getCall(1) + .calledWith( + takerTokenAddress, + takerAddress, + makerAddress, + bigNumberMatch(fillableAmount), + TradeSide.Taker, + TransferType.Trade, + ), ).to.be.true(); expect( - transferFromAsync.getCall(2).calledWith( - zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee), - TradeSide.Maker, TransferType.Fee, - ), + transferFromAsync + .getCall(2) + .calledWith( + zrxTokenAddress, + makerAddress, + feeRecipient, + bigNumberMatch(makerFee), + TradeSide.Maker, + TransferType.Fee, + ), ).to.be.true(); expect( - transferFromAsync.getCall(3).calledWith( - zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee), - TradeSide.Taker, TransferType.Fee, - ), + transferFromAsync + .getCall(3) + .calledWith( + zrxTokenAddress, + takerAddress, + feeRecipient, + bigNumberMatch(takerFee), + TradeSide.Taker, + TransferType.Fee, + ), ).to.be.true(); }); it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => { const makerFee = new BigNumber(2); const takerFee = new BigNumber(2); const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, takerTokenAddress, makerFee, takerFee, - makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient, + makerTokenAddress, + takerTokenAddress, + makerFee, + takerFee, + makerAddress, + ZeroEx.NULL_ADDRESS, + fillableAmount, + feeRecipient, ); await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress, + exchangeTransferSimulator, + signedOrder, + fillableAmount, + takerAddress, + zrxTokenAddress, ); expect(transferFromAsync.callCount).to.be.equal(4); expect( - transferFromAsync.getCall(0).calledWith( - makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount), - TradeSide.Maker, TransferType.Trade, - ), + transferFromAsync + .getCall(0) + .calledWith( + makerTokenAddress, + makerAddress, + takerAddress, + bigNumberMatch(fillableAmount), + TradeSide.Maker, + TransferType.Trade, + ), ).to.be.true(); expect( - transferFromAsync.getCall(1).calledWith( - takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount), - TradeSide.Taker, TransferType.Trade, - ), + transferFromAsync + .getCall(1) + .calledWith( + takerTokenAddress, + takerAddress, + makerAddress, + bigNumberMatch(fillableAmount), + TradeSide.Taker, + TransferType.Trade, + ), ).to.be.true(); expect( - transferFromAsync.getCall(2).calledWith( - zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee), - TradeSide.Maker, TransferType.Fee, - ), + transferFromAsync + .getCall(2) + .calledWith( + zrxTokenAddress, + makerAddress, + feeRecipient, + bigNumberMatch(makerFee), + TradeSide.Maker, + TransferType.Fee, + ), ).to.be.true(); expect( - transferFromAsync.getCall(3).calledWith( - zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee), - TradeSide.Taker, TransferType.Fee, - ), + transferFromAsync + .getCall(3) + .calledWith( + zrxTokenAddress, + takerAddress, + feeRecipient, + bigNumberMatch(takerFee), + TradeSide.Taker, + TransferType.Fee, + ), ).to.be.true(); }); it('should correctly round the fillMakerTokenAmount', async () => { const makerTokenAmount = new BigNumber(3); const takerTokenAmount = new BigNumber(1); const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + makerTokenAmount, + takerTokenAmount, ); await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress, + exchangeTransferSimulator, + signedOrder, + takerTokenAmount, + takerAddress, + zrxTokenAddress, ); expect(transferFromAsync.callCount).to.be.equal(4); const makerFillAmount = transferFromAsync.getCall(0).args[3]; @@ -314,12 +445,22 @@ describe('OrderValidation', () => { const makerFee = new BigNumber(2); const takerFee = new BigNumber(4); const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, - fillableAmount, ZeroEx.NULL_ADDRESS, + makerTokenAddress, + takerTokenAddress, + makerFee, + takerFee, + makerAddress, + takerAddress, + fillableAmount, + ZeroEx.NULL_ADDRESS, ); const fillTakerTokenAmount = fillableAmount.div(2).round(0); await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, + exchangeTransferSimulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, ); const makerPartialFee = makerFee.div(2); const takerPartialFee = takerFee.div(2); diff --git a/packages/0x.js/test/remaining_fillable_calculator_test.ts b/packages/0x.js/test/remaining_fillable_calculator_test.ts index 610bf9b1a..4c6b8f3ac 100644 --- a/packages/0x.js/test/remaining_fillable_calculator_test.ts +++ b/packages/0x.js/test/remaining_fillable_calculator_test.ts @@ -1,4 +1,4 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import 'mocha'; @@ -7,7 +7,6 @@ import { RemainingFillableCalculator } from '../src/order_watcher/remaining_fill import { ECSignature, SignedOrder } from '../src/types'; import { chaiSetup } from './utils/chai_setup'; -import { TokenUtils } from './utils/token_utils'; chaiSetup.configure(); const expect = chai.expect; @@ -27,29 +26,34 @@ describe('RemainingFillableCalculator', () => { const decimals: number = 4; const zero: BigNumber = new BigNumber(0); const zeroAddress = '0x0'; - const signature: ECSignature = { v: 27, r: '', s: ''}; + const signature: ECSignature = { v: 27, r: '', s: '' }; beforeEach(async () => { - [makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals)]; + [makerAmount, takerAmount, makerFeeAmount] = [ + ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals), + ]; [transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [ - ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals)]; + ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals), + ]; }); function buildSignedOrder(): SignedOrder { - return { ecSignature: signature, - exchangeContractAddress: zeroAddress, - feeRecipient: zeroAddress, - maker: zeroAddress, - taker: zeroAddress, - makerFee: makerFeeAmount, - takerFee: zero, - makerTokenAmount: makerAmount, - takerTokenAmount: takerAmount, - makerTokenAddress: makerToken, - takerTokenAddress: takerToken, - salt: zero, - expirationUnixTimestampSec: zero }; + return { + ecSignature: signature, + exchangeContractAddress: zeroAddress, + feeRecipient: zeroAddress, + maker: zeroAddress, + taker: zeroAddress, + makerFee: makerFeeAmount, + takerFee: zero, + makerTokenAmount: makerAmount, + takerTokenAmount: takerAmount, + makerTokenAddress: makerToken, + takerTokenAddress: takerToken, + salt: zero, + expirationUnixTimestampSec: zero, + }; } describe('Maker token is NOT ZRX', () => { before(async () => { @@ -58,23 +62,38 @@ describe('RemainingFillableCalculator', () => { it('calculates the correct amount when unfilled and funds available', () => { signedOrder = buildSignedOrder(); remainingMakerTokenAmount = signedOrder.makerTokenAmount; - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); }); it('calculates the correct amount when partially filled and funds available', () => { signedOrder = buildSignedOrder(); remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals); - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); }); it('calculates the amount to be 0 when all fee funds are transferred', () => { signedOrder = buildSignedOrder(); transferrableMakerFeeTokenAmount = zero; remainingMakerTokenAmount = signedOrder.makerTokenAmount; - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero); }); it('calculates the correct amount when balance is less than remaining fillable', () => { @@ -82,41 +101,58 @@ describe('RemainingFillableCalculator', () => { const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount); transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount); - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount); }); describe('Order to Fee Ratio is < 1', () => { beforeEach(async () => { - [makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals)]; + [makerAmount, takerAmount, makerFeeAmount] = [ + ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals), + ]; }); it('calculates the correct amount when funds unavailable', () => { signedOrder = buildSignedOrder(); remainingMakerTokenAmount = signedOrder.makerTokenAmount; const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount); - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, - remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount); }); }); describe('Ratio is not evenly divisble', () => { beforeEach(async () => { - [makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals), - ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals)]; + [makerAmount, takerAmount, makerFeeAmount] = [ + ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals), + ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals), + ]; }); it('calculates the correct amount when funds unavailable', () => { signedOrder = buildSignedOrder(); remainingMakerTokenAmount = signedOrder.makerTokenAmount; const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount); - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, - remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); const calculatedFillableAmount = calculator.computeRemainingMakerFillable(); expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true(); expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0)); @@ -135,15 +171,25 @@ describe('RemainingFillableCalculator', () => { transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount); transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount; - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); }); it('calculates the correct amount when partially filled and funds available', () => { signedOrder = buildSignedOrder(); remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals); - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); }); it('calculates the amount to be 0 when all fee funds are transferred', () => { @@ -151,8 +197,13 @@ describe('RemainingFillableCalculator', () => { transferrableMakerTokenAmount = zero; transferrableMakerFeeTokenAmount = zero; remainingMakerTokenAmount = signedOrder.makerTokenAmount; - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero); }); it('calculates the correct amount when balance is less than remaining fillable', () => { @@ -164,8 +215,13 @@ describe('RemainingFillableCalculator', () => { const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee); const expectedFillableAmount = new BigNumber(450980); - calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); + calculator = new RemainingFillableCalculator( + signedOrder, + isMakerTokenZRX, + transferrableMakerTokenAmount, + transferrableMakerFeeTokenAmount, + remainingMakerTokenAmount, + ); const calculatedFillableAmount = calculator.computeRemainingMakerFillable(); const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio); const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio); diff --git a/packages/0x.js/test/subscription_test.ts b/packages/0x.js/test/subscription_test.ts index 3aeeaa109..f4c6f748f 100644 --- a/packages/0x.js/test/subscription_test.ts +++ b/packages/0x.js/test/subscription_test.ts @@ -1,37 +1,26 @@ -import BigNumber from 'bignumber.js'; -import * as chai from 'chai'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import 'mocha'; import * as Sinon from 'sinon'; import * as Web3 from 'web3'; -import { - ApprovalContractEventArgs, - DecodedLogEvent, - Token, - TokenEvents, - ZeroEx, - ZeroExError, -} from '../src'; -import {BlockParamLiteral, DoneCallback} from '../src/types'; +import { ApprovalContractEventArgs, DecodedLogEvent, Token, TokenEvents, ZeroEx } from '../src'; +import { DoneCallback } from '../src/types'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {reportCallbackErrors} from './utils/report_callback_errors'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { assertNodeCallbackError } from './utils/report_callback_errors'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); describe('SubscriptionTest', () => { let web3: Web3; let zeroEx: ZeroEx; let userAddresses: string[]; let tokens: Token[]; - let tokenUtils: TokenUtils; let coinbase: string; let addressWithoutFunds: string; const config = { @@ -42,7 +31,6 @@ describe('SubscriptionTest', () => { zeroEx = new ZeroEx(web3.currentProvider, config); userAddresses = await zeroEx.getAvailableAddressesAsync(); tokens = await zeroEx.tokenRegistry.getTokensAsync(); - tokenUtils = new TokenUtils(tokens); coinbase = userAddresses[0]; addressWithoutFunds = userAddresses[1]; }); @@ -54,9 +42,7 @@ describe('SubscriptionTest', () => { }); describe('#subscribe', () => { const indexFilterValues = {}; - const shouldThrowOnInsufficientBalanceOrAllowance = true; let tokenAddress: string; - const transferAmount = new BigNumber(42); const allowanceAmount = new BigNumber(42); let stubs: Sinon.SinonStub[] = []; before(() => { @@ -71,50 +57,26 @@ describe('SubscriptionTest', () => { it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => { (async () => { const errMsg = 'Error fetching block'; - const callback = reportCallbackErrors(done)( - (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { - expect(err.message).to.be.equal(errMsg); - expect(logEvent).to.be.undefined(); - done(); - }, - ); - stubs = [ - Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync') - .throws(new Error(errMsg)), - ]; - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Approval, indexFilterValues, callback); + const callback = assertNodeCallbackError(done, errMsg); + stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))]; + zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount); })().catch(done); }); it('Should receive the Error when an error occurs while reconciling the new block', (done: DoneCallback) => { (async () => { const errMsg = 'Error fetching logs'; - const callback = reportCallbackErrors(done)( - (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { - expect(err.message).to.be.equal(errMsg); - expect(logEvent).to.be.undefined(); - done(); - }, - ); - stubs = [ - Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync') - .throws(new Error(errMsg)), - ]; - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Approval, indexFilterValues, callback); + const callback = assertNodeCallbackError(done, errMsg); + stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))]; + zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount); })().catch(done); }); it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => { (async () => { - const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop; - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Approval, indexFilterValues, callback); - stubs = [ - Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync') - .throws(new Error('JSON RPC error')), - ]; + const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop; + zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); + stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))]; zeroEx.token.unsubscribeAll(); done(); })().catch(done); diff --git a/packages/0x.js/test/token_registry_wrapper_test.ts b/packages/0x.js/test/token_registry_wrapper_test.ts index f1f307f3a..0a170db8f 100644 --- a/packages/0x.js/test/token_registry_wrapper_test.ts +++ b/packages/0x.js/test/token_registry_wrapper_test.ts @@ -1,28 +1,28 @@ -import {schemas, SchemaValidator} from '@0xproject/json-schemas'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { schemas, SchemaValidator } from '@0xproject/json-schemas'; import * as chai from 'chai'; import * as _ from 'lodash'; import 'mocha'; -import {Token, ZeroEx} from '../src'; +import { Token, ZeroEx } from '../src'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7; describe('TokenRegistryWrapper', () => { let zeroEx: ZeroEx; let tokens: Token[]; - const tokenAddressBySymbol: {[symbol: string]: string} = {}; - const tokenAddressByName: {[symbol: string]: string} = {}; - const tokenBySymbol: {[symbol: string]: Token} = {}; - const tokenByName: {[symbol: string]: Token} = {}; + const tokenAddressBySymbol: { [symbol: string]: string } = {}; + const tokenAddressByName: { [symbol: string]: string } = {}; + const tokenBySymbol: { [symbol: string]: Token } = {}; + const tokenByName: { [symbol: string]: Token } = {}; const registeredSymbol = 'ZRX'; const registeredName = '0x Protocol Token'; const unregisteredSymbol = 'MAL'; diff --git a/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts b/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts index 05861d112..15bd7a8ba 100644 --- a/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts +++ b/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts @@ -1,11 +1,10 @@ import * as chai from 'chai'; -import {ZeroEx} from '../src'; -import {TokenTransferProxyWrapper} from '../src/contract_wrappers/token_transfer_proxy_wrapper'; +import { ZeroEx } from '../src'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; diff --git a/packages/0x.js/test/token_wrapper_test.ts b/packages/0x.js/test/token_wrapper_test.ts index ae6016869..4ba1f07c5 100644 --- a/packages/0x.js/test/token_wrapper_test.ts +++ b/packages/0x.js/test/token_wrapper_test.ts @@ -1,35 +1,32 @@ -import {promisify} from '@0xproject/utils'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import BigNumber from 'bignumber.js'; +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import 'mocha'; import * as Web3 from 'web3'; import { ApprovalContractEventArgs, - ContractEvent, + BlockParamLiteral, + BlockRange, DecodedLogEvent, - LogEvent, - LogWithDecodedArgs, - SubscriptionOpts, Token, - TokenContractEventArgs, TokenEvents, TransferContractEventArgs, ZeroEx, ZeroExError, } from '../src'; -import {BlockParamLiteral, DoneCallback} from '../src/types'; +import { DoneCallback } from '../src/types'; -import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {chaiSetup} from './utils/chai_setup'; -import {constants} from './utils/constants'; -import {TokenUtils} from './utils/token_utils'; -import {web3Factory} from './utils/web3_factory'; +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { reportNodeCallbackErrors } from './utils/report_callback_errors'; +import { TokenUtils } from './utils/token_utils'; +import { web3Factory } from './utils/web3_factory'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(); +const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL); describe('TokenWrapper', () => { let web3: Web3; @@ -71,25 +68,24 @@ describe('TokenWrapper', () => { const toAddress = addressWithoutFunds; const preBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress); expect(preBalance).to.be.bignumber.equal(0); - const txHash = await zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount); - const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); + await zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount); const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress); return expect(postBalance).to.be.bignumber.equal(transferAmount); }); it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => { const fromAddress = addressWithoutFunds; const toAddress = coinbase; - return expect(zeroEx.token.transferAsync( - token.address, fromAddress, toAddress, transferAmount, - )).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer); + return expect( + zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount), + ).to.be.rejectedWith(ZeroExError.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(zeroEx.token.transferAsync( - nonExistentTokenAddress, fromAddress, toAddress, transferAmount, - )).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); + return expect( + zeroEx.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount), + ).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); }); }); describe('#transferFromAsync', () => { @@ -108,24 +104,22 @@ describe('TokenWrapper', () => { const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress); expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount); - const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, - toAddress); + const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, toAddress); expect(fromAddressAllowance).to.be.bignumber.equal(0); - return expect(zeroEx.token.transferFromAsync( - token.address, fromAddress, toAddress, senderAddress, transferAmount, - )).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer); + return expect( + zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount), + ).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer); }); - it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', - async () => { + it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => { const fromAddress = coinbase; const transferAmount = new BigNumber(42); await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount); - return expect(zeroEx.token.transferFromAsync( - token.address, fromAddress, toAddress, senderAddress, transferAmount, - )).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer); + return expect( + zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount), + ).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer); }); it('should fail to transfer tokens if fromAddress has insufficient balance', async () => { const fromAddress = addressWithoutFunds; @@ -135,13 +129,16 @@ describe('TokenWrapper', () => { expect(fromAddressBalance).to.be.bignumber.equal(0); await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount); - const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, - senderAddress); + const fromAddressAllowance = await zeroEx.token.getAllowanceAsync( + token.address, + fromAddress, + senderAddress, + ); expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount); - return expect(zeroEx.token.transferFromAsync( - token.address, fromAddress, toAddress, senderAddress, transferAmount, - )).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer); + return expect( + zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount), + ).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer); }); it('should successfully transfer tokens', async () => { const fromAddress = coinbase; @@ -152,17 +149,22 @@ describe('TokenWrapper', () => { const transferAmount = new BigNumber(42); await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount); - await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, - transferAmount); + await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount); const postBalance = await zeroEx.token.getBalanceAsync(token.address, 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(zeroEx.token.transferFromAsync( - nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42), - )).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); + return expect( + zeroEx.token.transferFromAsync( + nonExistentTokenAddress, + fromAddress, + toAddress, + senderAddress, + new BigNumber(42), + ), + ).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); }); }); describe('#getBalanceAsync', () => { @@ -177,8 +179,9 @@ describe('TokenWrapper', () => { it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; const ownerAddress = coinbase; - return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)) - .to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); + return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)).to.be.rejectedWith( + ZeroExError.TokenContractDoesNotExist, + ); }); it('should return a balance of 0 for a non-existent owner address', async () => { const token = tokens[0]; @@ -196,22 +199,25 @@ describe('TokenWrapper', () => { zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config); }); it('should return balance even when called with Web3 provider instance without addresses', async () => { - const token = tokens[0]; - const ownerAddress = coinbase; - const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress); - const expectedBalance = new BigNumber('1000000000000000000000000000'); - return expect(balance).to.be.bignumber.equal(expectedBalance); + const token = tokens[0]; + const ownerAddress = coinbase; + const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress); + const expectedBalance = new BigNumber('1000000000000000000000000000'); + return expect(balance).to.be.bignumber.equal(expectedBalance); }); }); }); describe('#setAllowanceAsync', () => { - it('should set the spender\'s allowance', async () => { + it("should set the spender's allowance", async () => { const token = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; - const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, - spenderAddress); + const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync( + token.address, + ownerAddress, + spenderAddress, + ); const expectedAllowanceBeforeAllowanceSet = new BigNumber(0); expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet); @@ -224,7 +230,7 @@ describe('TokenWrapper', () => { }); }); describe('#setUnlimitedAllowanceAsync', () => { - it('should set the unlimited spender\'s allowance', async () => { + it("should set the unlimited spender's allowance", async () => { const token = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; @@ -246,10 +252,18 @@ describe('TokenWrapper', () => { ); await zeroEx.token.transferFromAsync( - zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount, + zrx.address, + coinbase, + userWithNormalAllowance, + userWithNormalAllowance, + transferAmount, ); await zeroEx.token.transferFromAsync( - zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount, + zrx.address, + coinbase, + userWithUnlimitedAllowance, + userWithUnlimitedAllowance, + transferAmount, ); const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); @@ -305,7 +319,9 @@ describe('TokenWrapper', () => { await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits); const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync( - token.address, ownerAddress, spenderAddress, + token.address, + ownerAddress, + spenderAddress, ); const expectedAllowance = amountInBaseUnits; return expect(allowance).to.be.bignumber.equal(expectedAllowance); @@ -354,7 +370,6 @@ describe('TokenWrapper', () => { }); describe('#subscribe', () => { const indexFilterValues = {}; - const shouldThrowOnInsufficientBalanceOrAllowance = true; let tokenAddress: string; const transferAmount = new BigNumber(42); const allowanceAmount = new BigNumber(42); @@ -372,65 +387,66 @@ describe('TokenWrapper', () => { // Source: https://github.com/mochajs/mocha/issues/2407 it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { (async () => { - const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - expect(logEvent.log.logIndex).to.be.equal(0); - expect(logEvent.log.transactionIndex).to.be.equal(0); - expect(logEvent.log.blockNumber).to.be.a('number'); - const args = logEvent.log.args; - expect(args._from).to.be.equal(coinbase); - expect(args._to).to.be.equal(addressWithoutFunds); - expect(args._value).to.be.bignumber.equal(transferAmount); - done(); - }; - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Transfer, indexFilterValues, callback); + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<TransferContractEventArgs>) => { + expect(logEvent.isRemoved).to.be.false(); + expect(logEvent.log.logIndex).to.be.equal(0); + expect(logEvent.log.transactionIndex).to.be.equal(0); + expect(logEvent.log.blockNumber).to.be.a('number'); + const args = logEvent.log.args; + expect(args._from).to.be.equal(coinbase); + expect(args._to).to.be.equal(addressWithoutFunds); + expect(args._value).to.be.bignumber.equal(transferAmount); + }, + ); + zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback); await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); })().catch(done); }); it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { (async () => { - const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - const args = logEvent.log.args; - expect(args._owner).to.be.equal(coinbase); - expect(args._spender).to.be.equal(addressWithoutFunds); - expect(args._value).to.be.bignumber.equal(allowanceAmount); - done(); - }; - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Approval, indexFilterValues, callback); + const callback = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + expect(logEvent).to.not.be.undefined(); + expect(logEvent.isRemoved).to.be.false(); + const args = logEvent.log.args; + expect(args._owner).to.be.equal(coinbase); + expect(args._spender).to.be.equal(addressWithoutFunds); + expect(args._value).to.be.bignumber.equal(allowanceAmount); + }, + ); + zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount); })().catch(done); }); it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => { (async () => { - const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { - done(new Error('Expected this subscription to have been cancelled')); - }; - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled, + const callbackNeverToBeCalled = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, ); - const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { - done(); - }; + zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled); + const callbackToBeCalled = reportNodeCallbackErrors(done)(); const newProvider = web3Factory.getRpcProvider(); zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID); - zeroEx.token.subscribe( - tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled, - ); + zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled); await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); })().catch(done); }); it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { (async () => { - const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { - done(new Error('Expected this subscription to have been cancelled')); - }; + const callbackNeverToBeCalled = reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, + ); const subscriptionToken = zeroEx.token.subscribe( - tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled); + tokenAddress, + TokenEvents.Transfer, + indexFilterValues, + callbackNeverToBeCalled, + ); zeroEx.token.unsubscribe(subscriptionToken); await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); done(); @@ -440,7 +456,7 @@ describe('TokenWrapper', () => { describe('#getLogsAsync', () => { let tokenAddress: string; let tokenTransferProxyAddress: string; - const subscriptionOpts: SubscriptionOpts = { + const blockRange: BlockRange = { fromBlock: 0, toBlock: BlockParamLiteral.Latest, }; @@ -456,7 +472,10 @@ describe('TokenWrapper', () => { const eventName = TokenEvents.Approval; const indexFilterValues = {}; const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>( - tokenAddress, eventName, subscriptionOpts, indexFilterValues, + tokenAddress, + eventName, + blockRange, + indexFilterValues, ); expect(logs).to.have.length(1); const args = logs[0].args; @@ -471,7 +490,10 @@ describe('TokenWrapper', () => { const differentEventName = TokenEvents.Transfer; const indexFilterValues = {}; const logs = await zeroEx.token.getLogsAsync( - tokenAddress, differentEventName, subscriptionOpts, indexFilterValues, + tokenAddress, + differentEventName, + blockRange, + indexFilterValues, ); expect(logs).to.have.length(0); }); @@ -485,7 +507,10 @@ describe('TokenWrapper', () => { _owner: coinbase, }; const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>( - tokenAddress, eventName, subscriptionOpts, indexFilterValues, + tokenAddress, + eventName, + blockRange, + indexFilterValues, ); expect(logs).to.have.length(1); const args = logs[0].args; @@ -493,3 +518,4 @@ describe('TokenWrapper', () => { }); }); }); +// tslint:disable:max-file-line-count diff --git a/packages/0x.js/test/utils/blockchain_lifecycle.ts b/packages/0x.js/test/utils/blockchain_lifecycle.ts deleted file mode 100644 index 9a44ccd6f..000000000 --- a/packages/0x.js/test/utils/blockchain_lifecycle.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {RPC} from './rpc'; - -export class BlockchainLifecycle { - private rpc: RPC; - private snapshotIdsStack: number[]; - constructor() { - this.rpc = new RPC(); - this.snapshotIdsStack = []; - } - // TODO: In order to run these tests on an actual node, we should check if we are running against - // TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test - public async startAsync(): Promise<void> { - const snapshotId = await this.rpc.takeSnapshotAsync(); - this.snapshotIdsStack.push(snapshotId); - } - public async revertAsync(): Promise<void> { - const snapshotId = this.snapshotIdsStack.pop() as number; - const didRevert = await this.rpc.revertSnapshotAsync(snapshotId); - if (!didRevert) { - throw new Error(`Snapshot with id #${snapshotId} failed to revert`); - } - } - public async mineABlock(): Promise<void> { - await this.rpc.mineBlockAsync(); - } -} diff --git a/packages/0x.js/test/utils/constants.ts b/packages/0x.js/test/utils/constants.ts index 75fdf49c9..a9e665c25 100644 --- a/packages/0x.js/test/utils/constants.ts +++ b/packages/0x.js/test/utils/constants.ts @@ -1,12 +1,11 @@ export const constants = { NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - RPC_HOST: 'localhost', - RPC_PORT: 8545, + RPC_URL: 'http://localhost:8545', ROPSTEN_NETWORK_ID: 3, KOVAN_NETWORK_ID: 42, TESTRPC_NETWORK_ID: 50, - KOVAN_RPC_URL: 'https://kovan.infura.io', - ROPSTEN_RPC_URL: 'https://ropsten.infura.io', + KOVAN_RPC_URL: 'https://kovan.infura.io/', + ROPSTEN_RPC_URL: 'https://ropsten.infura.io/', ZRX_DECIMALS: 18, GAS_ESTIMATE: 500000, }; diff --git a/packages/0x.js/test/utils/fill_scenarios.ts b/packages/0x.js/test/utils/fill_scenarios.ts index 090493935..1a61487f4 100644 --- a/packages/0x.js/test/utils/fill_scenarios.ts +++ b/packages/0x.js/test/utils/fill_scenarios.ts @@ -1,116 +1,202 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; -import {SignedOrder, Token, ZeroEx} from '../../src'; -import {orderFactory} from '../utils/order_factory'; +import { SignedOrder, Token, ZeroEx } from '../../src'; +import { artifacts } from '../../src/artifacts'; +import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token'; +import { orderFactory } from '../utils/order_factory'; -import {constants} from './constants'; +import { constants } from './constants'; + +const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100); export class FillScenarios { - private zeroEx: ZeroEx; - private userAddresses: string[]; - private tokens: Token[]; - private coinbase: string; - private zrxTokenAddress: string; - private exchangeContractAddress: string; - constructor(zeroEx: ZeroEx, userAddresses: string[], - tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) { - this.zeroEx = zeroEx; - this.userAddresses = userAddresses; - this.tokens = tokens; - this.coinbase = userAddresses[0]; - this.zrxTokenAddress = zrxTokenAddress; - this.exchangeContractAddress = exchangeContractAddress; + private _zeroEx: ZeroEx; + private _userAddresses: string[]; + private _tokens: Token[]; + private _coinbase: string; + private _zrxTokenAddress: string; + private _exchangeContractAddress: string; + constructor( + zeroEx: ZeroEx, + userAddresses: string[], + tokens: Token[], + zrxTokenAddress: string, + exchangeContractAddress: string, + ) { + this._zeroEx = zeroEx; + this._userAddresses = userAddresses; + this._tokens = tokens; + this._coinbase = userAddresses[0]; + this._zrxTokenAddress = zrxTokenAddress; + this._exchangeContractAddress = exchangeContractAddress; + } + public async initTokenBalancesAsync() { + const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper; + for (const token of this._tokens) { + if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') { + const contractInstance = web3Wrapper.getContractInstance( + artifacts.DummyTokenArtifact.abi, + token.address, + ); + const defaults = {}; + const dummyToken = new DummyTokenContract(contractInstance, defaults); + const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals); + const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, { + from: this._coinbase, + }); + await this._zeroEx.awaitTransactionMinedAsync(txHash); + } + } } - public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, - makerAddress: string, takerAddress: string, - fillableAmount: BigNumber, - expirationUnixTimestampSec?: BigNumber): - Promise<SignedOrder> { + public async createFillableSignedOrderAsync( + makerTokenAddress: string, + takerTokenAddress: string, + makerAddress: string, + takerAddress: string, + fillableAmount: BigNumber, + expirationUnixTimestampSec?: BigNumber, + ): Promise<SignedOrder> { return this.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - fillableAmount, fillableAmount, expirationUnixTimestampSec, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + fillableAmount, + expirationUnixTimestampSec, ); } public async createFillableSignedOrderWithFeesAsync( - makerTokenAddress: string, takerTokenAddress: string, - makerFee: BigNumber, takerFee: BigNumber, - makerAddress: string, takerAddress: string, + makerTokenAddress: string, + takerTokenAddress: string, + makerFee: BigNumber, + takerFee: BigNumber, + makerAddress: string, + takerAddress: string, fillableAmount: BigNumber, - feeRecepient: string, expirationUnixTimestampSec?: BigNumber, + feeRecepient: string, + expirationUnixTimestampSec?: BigNumber, ): Promise<SignedOrder> { - return this.createAsymmetricFillableSignedOrderWithFeesAsync( - makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, - fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec, + return this._createAsymmetricFillableSignedOrderWithFeesAsync( + makerTokenAddress, + takerTokenAddress, + makerFee, + takerFee, + makerAddress, + takerAddress, + fillableAmount, + fillableAmount, + feeRecepient, + expirationUnixTimestampSec, ); } public async createAsymmetricFillableSignedOrderAsync( - makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string, - makerFillableAmount: BigNumber, takerFillableAmount: BigNumber, - expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> { + makerTokenAddress: string, + takerTokenAddress: string, + makerAddress: string, + takerAddress: string, + makerFillableAmount: BigNumber, + takerFillableAmount: BigNumber, + expirationUnixTimestampSec?: BigNumber, + ): Promise<SignedOrder> { const makerFee = new BigNumber(0); const takerFee = new BigNumber(0); const feeRecepient = constants.NULL_ADDRESS; - return this.createAsymmetricFillableSignedOrderWithFeesAsync( - makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, - makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec, + return this._createAsymmetricFillableSignedOrderWithFeesAsync( + makerTokenAddress, + takerTokenAddress, + makerFee, + takerFee, + makerAddress, + takerAddress, + makerFillableAmount, + takerFillableAmount, + feeRecepient, + expirationUnixTimestampSec, ); } - public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, - takerAddress: string, fillableAmount: BigNumber, - partialFillAmount: BigNumber) { - const [makerAddress] = this.userAddresses; + public async createPartiallyFilledSignedOrderAsync( + makerTokenAddress: string, + takerTokenAddress: string, + takerAddress: string, + fillableAmount: BigNumber, + partialFillAmount: BigNumber, + ) { + const [makerAddress] = this._userAddresses; const signedOrder = await this.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, - fillableAmount, fillableAmount, + makerTokenAddress, + takerTokenAddress, + makerAddress, + takerAddress, + fillableAmount, + fillableAmount, ); const shouldThrowOnInsufficientBalanceOrAllowance = false; - await this.zeroEx.exchange.fillOrderAsync( - signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + await this._zeroEx.exchange.fillOrderAsync( + signedOrder, + partialFillAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + takerAddress, ); return signedOrder; } - private async createAsymmetricFillableSignedOrderWithFeesAsync( - makerTokenAddress: string, takerTokenAddress: string, - makerFee: BigNumber, takerFee: BigNumber, - makerAddress: string, takerAddress: string, - makerFillableAmount: BigNumber, takerFillableAmount: BigNumber, - feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> { - + private async _createAsymmetricFillableSignedOrderWithFeesAsync( + makerTokenAddress: string, + takerTokenAddress: string, + makerFee: BigNumber, + takerFee: BigNumber, + makerAddress: string, + takerAddress: string, + makerFillableAmount: BigNumber, + takerFillableAmount: BigNumber, + feeRecepient: string, + expirationUnixTimestampSec?: BigNumber, + ): Promise<SignedOrder> { await Promise.all([ - this.increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount), - this.increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount), + this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount), + this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount), ]); await Promise.all([ - this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, makerAddress, makerFee), - this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, takerAddress, takerFee), + this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee), + this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee), ]); - const signedOrder = await orderFactory.createSignedOrderAsync(this.zeroEx, - makerAddress, takerAddress, makerFee, takerFee, - makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress, - this.exchangeContractAddress, feeRecepient, expirationUnixTimestampSec); + const signedOrder = await orderFactory.createSignedOrderAsync( + this._zeroEx, + makerAddress, + takerAddress, + makerFee, + takerFee, + makerFillableAmount, + makerTokenAddress, + takerFillableAmount, + takerTokenAddress, + this._exchangeContractAddress, + feeRecepient, + expirationUnixTimestampSec, + ); return signedOrder; } - private async increaseBalanceAndAllowanceAsync( - tokenAddress: string, address: string, amount: BigNumber): Promise<void> { + private async _increaseBalanceAndAllowanceAsync( + tokenAddress: string, + address: string, + amount: BigNumber, + ): Promise<void> { if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) { return; // noop } await Promise.all([ - this.increaseBalanceAsync(tokenAddress, address, amount), - this.increaseAllowanceAsync(tokenAddress, address, amount), + this._increaseBalanceAsync(tokenAddress, address, amount), + this._increaseAllowanceAsync(tokenAddress, address, amount), ]); } - private async increaseBalanceAsync( - tokenAddress: string, address: string, amount: BigNumber): Promise<void> { - await this.zeroEx.token.transferAsync(tokenAddress, this.coinbase, address, amount); + private async _increaseBalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> { + await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount); } - private async increaseAllowanceAsync( - tokenAddress: string, address: string, amount: BigNumber): Promise<void> { - const oldMakerAllowance = await this.zeroEx.token.getProxyAllowanceAsync(tokenAddress, address); + private async _increaseAllowanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> { + const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address); const newMakerAllowance = oldMakerAllowance.plus(amount); - await this.zeroEx.token.setProxyAllowanceAsync( - tokenAddress, address, newMakerAllowance, - ); + await this._zeroEx.token.setProxyAllowanceAsync(tokenAddress, address, newMakerAllowance); } } diff --git a/packages/0x.js/test/utils/order_factory.ts b/packages/0x.js/test/utils/order_factory.ts index 41d93e340..60a7c5fb2 100644 --- a/packages/0x.js/test/utils/order_factory.ts +++ b/packages/0x.js/test/utils/order_factory.ts @@ -1,7 +1,7 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {SignedOrder, ZeroEx} from '../../src'; +import { SignedOrder, ZeroEx } from '../../src'; export const orderFactory = { async createSignedOrderAsync( @@ -16,11 +16,12 @@ export const orderFactory = { takerTokenAddress: string, exchangeContractAddress: string, feeRecipient: string, - expirationUnixTimestampSecIfExists?: BigNumber): Promise<SignedOrder> { + expirationUnixTimestampSecIfExists?: BigNumber, + ): Promise<SignedOrder> { const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite - const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) ? - defaultExpirationUnixTimestampSec : - expirationUnixTimestampSecIfExists; + const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) + ? defaultExpirationUnixTimestampSec + : expirationUnixTimestampSecIfExists; const order = { maker, taker, @@ -37,7 +38,7 @@ export const orderFactory = { }; const orderHash = ZeroEx.getOrderHashHex(order); const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker); - const signedOrder: SignedOrder = _.assign(order, {ecSignature}); + const signedOrder: SignedOrder = _.assign(order, { ecSignature }); return signedOrder; }, }; diff --git a/packages/0x.js/test/utils/report_callback_errors.ts b/packages/0x.js/test/utils/report_callback_errors.ts index 8a8f4d966..27c9745c9 100644 --- a/packages/0x.js/test/utils/report_callback_errors.ts +++ b/packages/0x.js/test/utils/report_callback_errors.ts @@ -1,10 +1,22 @@ +import * as chai from 'chai'; +import * as _ from 'lodash'; + import { DoneCallback } from '../../src/types'; -export const reportCallbackErrors = (done: DoneCallback) => { - return (f: (...args: any[]) => void) => { - const wrapped = async (...args: any[]) => { +const expect = chai.expect; + +export const reportNoErrorCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => { + return <T>(f?: (value: T) => void) => { + const wrapped = (value: T) => { + if (_.isUndefined(f)) { + done(); + return; + } try { - f(...args); + f(value); + if (expectToBeCalledOnce) { + done(); + } } catch (err) { done(err); } @@ -12,3 +24,43 @@ export const reportCallbackErrors = (done: DoneCallback) => { return wrapped; }; }; + +export const reportNodeCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => { + return <T>(f?: (value: T) => void) => { + const wrapped = (error: Error | null, value: T | undefined) => { + if (!_.isNull(error)) { + done(error); + } else { + if (_.isUndefined(f)) { + done(); + return; + } + try { + f(value as T); + if (expectToBeCalledOnce) { + done(); + } + } catch (err) { + done(err); + } + } + }; + return wrapped; + }; +}; + +export const assertNodeCallbackError = (done: DoneCallback, errMsg: string) => { + const wrapped = <T>(error: Error | null, value: T | undefined) => { + if (_.isNull(error)) { + done(new Error('Expected callback to receive an error')); + } else { + try { + expect(error.message).to.be.equal(errMsg); + done(); + } catch (err) { + done(err); + } + } + }; + return wrapped; +}; diff --git a/packages/0x.js/test/utils/rpc.ts b/packages/0x.js/test/utils/rpc.ts deleted file mode 100644 index 309a96d5e..000000000 --- a/packages/0x.js/test/utils/rpc.ts +++ /dev/null @@ -1,58 +0,0 @@ -import * as ethUtil from 'ethereumjs-util'; -import * as request from 'request-promise-native'; - -import {constants} from './constants'; - -export class RPC { - private host: string; - private port: number; - private id: number; - constructor() { - this.host = constants.RPC_HOST; - this.port = constants.RPC_PORT; - this.id = 0; - } - public async takeSnapshotAsync(): Promise<number> { - const method = 'evm_snapshot'; - const params: any[] = []; - const payload = this.toPayload(method, params); - const snapshotIdHex = await this.sendAsync(payload); - const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex)); - return snapshotId; - } - public async revertSnapshotAsync(snapshotId: number): Promise<boolean> { - const method = 'evm_revert'; - const params = [snapshotId]; - const payload = this.toPayload(method, params); - const didRevert = await this.sendAsync(payload); - return didRevert; - } - public async mineBlockAsync(): Promise<void> { - const method = 'evm_mine'; - const params: any[] = []; - const payload = this.toPayload(method, params); - await this.sendAsync(payload); - } - private toPayload(method: string, params: any[] = []): string { - const payload = JSON.stringify({ - id: this.id, - method, - params, - }); - this.id += 1; - return payload; - } - private async sendAsync(payload: string): Promise<any> { - const opts = { - method: 'POST', - uri: `http://${this.host}:${this.port}`, - body: payload, - headers: { - 'content-type': 'application/json', - }, - }; - const bodyString = await request(opts); - const body = JSON.parse(bodyString); - return body.result; - } -} diff --git a/packages/0x.js/test/utils/subproviders/empty_wallet_subprovider.ts b/packages/0x.js/test/utils/subproviders/empty_wallet_subprovider.ts index e5e279873..53f2be83d 100644 --- a/packages/0x.js/test/utils/subproviders/empty_wallet_subprovider.ts +++ b/packages/0x.js/test/utils/subproviders/empty_wallet_subprovider.ts @@ -1,4 +1,4 @@ -import {JSONRPCPayload} from '../../../src/types'; +import { JSONRPCPayload } from '../../../src/types'; /* * This class implements the web3-provider-engine subprovider interface and returns @@ -8,7 +8,7 @@ import {JSONRPCPayload} from '../../../src/types'; export class EmptyWalletSubprovider { // This method needs to be here to satisfy the interface but linter wants it to be static. // tslint:disable-next-line:prefer-function-over-method - public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) { + public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error | null, result: any) => void) { switch (payload.method) { case 'eth_accounts': end(null, []); diff --git a/packages/0x.js/test/utils/subproviders/fake_gas_estimate_subprovider.ts b/packages/0x.js/test/utils/subproviders/fake_gas_estimate_subprovider.ts index 059163f2e..e1113a851 100644 --- a/packages/0x.js/test/utils/subproviders/fake_gas_estimate_subprovider.ts +++ b/packages/0x.js/test/utils/subproviders/fake_gas_estimate_subprovider.ts @@ -1,4 +1,4 @@ -import {JSONRPCPayload} from '../../../src/types'; +import { JSONRPCPayload } from '../../../src/types'; /* * This class implements the web3-provider-engine subprovider interface and returns @@ -9,16 +9,16 @@ import {JSONRPCPayload} from '../../../src/types'; * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js */ export class FakeGasEstimateSubprovider { - private constantGasAmount: number; + private _constantGasAmount: number; constructor(constantGasAmount: number) { - this.constantGasAmount = constantGasAmount; + this._constantGasAmount = constantGasAmount; } // This method needs to be here to satisfy the interface but linter wants it to be static. // tslint:disable-next-line:prefer-function-over-method - public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) { + public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error | null, result: any) => void) { switch (payload.method) { case 'eth_estimateGas': - end(null, this.constantGasAmount); + end(null, this._constantGasAmount); return; default: diff --git a/packages/0x.js/test/utils/token_utils.ts b/packages/0x.js/test/utils/token_utils.ts index 9c20f52a1..d3fc22ff4 100644 --- a/packages/0x.js/test/utils/token_utils.ts +++ b/packages/0x.js/test/utils/token_utils.ts @@ -1,25 +1,33 @@ import * as _ from 'lodash'; -import {InternalZeroExError, Token} from '../../src/types'; +import { InternalZeroExError, Token } from '../../src/types'; const PROTOCOL_TOKEN_SYMBOL = 'ZRX'; +const WETH_TOKEN_SYMBOL = 'WETH'; export class TokenUtils { - private tokens: Token[]; + private _tokens: Token[]; constructor(tokens: Token[]) { - this.tokens = tokens; + this._tokens = tokens; } public getProtocolTokenOrThrow(): Token { - const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL}); + const zrxToken = _.find(this._tokens, { symbol: PROTOCOL_TOKEN_SYMBOL }); if (_.isUndefined(zrxToken)) { throw new Error(InternalZeroExError.ZrxNotInTokenRegistry); } return zrxToken; } - public getNonProtocolTokens(): Token[] { - const nonProtocolTokens = _.filter(this.tokens, token => { - return token.symbol !== PROTOCOL_TOKEN_SYMBOL; + public getWethTokenOrThrow(): Token { + const wethToken = _.find(this._tokens, { symbol: WETH_TOKEN_SYMBOL }); + if (_.isUndefined(wethToken)) { + throw new Error(InternalZeroExError.WethNotInTokenRegistry); + } + return wethToken; + } + public getDummyTokens(): Token[] { + const dummyTokens = _.filter(this._tokens, token => { + return !_.includes([PROTOCOL_TOKEN_SYMBOL, WETH_TOKEN_SYMBOL], token.symbol); }); - return nonProtocolTokens; + return dummyTokens; } } diff --git a/packages/0x.js/test/utils/web3_factory.ts b/packages/0x.js/test/utils/web3_factory.ts index da4828943..26c26e03d 100644 --- a/packages/0x.js/test/utils/web3_factory.ts +++ b/packages/0x.js/test/utils/web3_factory.ts @@ -3,14 +3,20 @@ // we are not running in a browser env. // Filed issue: https://github.com/ethereum/web3.js/issues/844 (global as any).XMLHttpRequest = undefined; -import * as Web3 from 'web3'; import ProviderEngine = require('web3-provider-engine'); import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); -import {EmptyWalletSubprovider} from './subproviders/empty_wallet_subprovider'; -import {FakeGasEstimateSubprovider} from './subproviders/fake_gas_estimate_subprovider'; +import { EmptyWalletSubprovider } from './subproviders/empty_wallet_subprovider'; +import { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_subprovider'; + +import { constants } from './constants'; -import {constants} from './constants'; +// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang +// because they are using the wrong XHR package. +// importing web3 after subproviders fixes this issue +// Filed issue: https://github.com/ethereum/web3.js/issues/844 +// tslint:disable-next-line:ordered-imports +import * as Web3 from 'web3'; export const web3Factory = { create(hasAddresses: boolean = true): Web3 { @@ -21,14 +27,15 @@ export const web3Factory = { }, getRpcProvider(hasAddresses: boolean = true): Web3.Provider { const provider = new ProviderEngine(); - const rpcUrl = `http://${constants.RPC_HOST}:${constants.RPC_PORT}`; if (!hasAddresses) { provider.addProvider(new EmptyWalletSubprovider()); } provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE)); - provider.addProvider(new RpcSubprovider({ - rpcUrl, - })); + provider.addProvider( + new RpcSubprovider({ + rpcUrl: constants.RPC_URL, + }), + ); provider.start(); return provider; }, diff --git a/packages/0x.js/tsconfig.json b/packages/0x.js/tsconfig.json index a5da86b88..117f51e83 100644 --- a/packages/0x.js/tsconfig.json +++ b/packages/0x.js/tsconfig.json @@ -1,22 +1,16 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2015", "dom" ], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "experimentalDecorators": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*", - "./test/**/*", - "../../node_modules/types-bn/index.d.ts", - "../../node_modules/types-ethereumjs-util/index.d.ts", - "../../node_modules/web3-typescript-typings/index.d.ts", - "../../node_modules/chai-typescript-typings/index.d.ts", - "../../node_modules/chai-as-promised-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib", + "noImplicitThis": false + }, + "include": [ + "./src/**/*", + "./test/**/*", + "../../node_modules/types-bn/index.d.ts", + "../../node_modules/types-ethereumjs-util/index.d.ts", + "../../node_modules/web3-typescript-typings/index.d.ts", + "../../node_modules/chai-typescript-typings/index.d.ts", + "../../node_modules/chai-as-promised-typescript-typings/index.d.ts" + ] } diff --git a/packages/0x.js/tslint.json b/packages/0x.js/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/0x.js/tslint.json +++ b/packages/0x.js/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/0x.js/webpack.config.js b/packages/0x.js/webpack.config.js index 61a7e4196..2c1fe81a7 100644 --- a/packages/0x.js/webpack.config.js +++ b/packages/0x.js/webpack.config.js @@ -7,10 +7,10 @@ const path = require('path'); const production = process.env.NODE_ENV === 'production'; let entry = { - 'index': './src/index.ts', + index: './src/index.ts', }; if (production) { - entry = _.assign({}, entry, {'index.min': './src/index.ts'}); + entry = _.assign({}, entry, { 'index.min': './src/index.ts' }); } module.exports = { |